General Setup


Create a new analysis directories.

- general directory

- for plots

- for output of summary results

- for baseline tables
source("scripts/functions.R")
source("scripts/pack02.packages.R")

* General packages...

* Genomic packages...
# Today = format(as.Date(as.POSIXlt(Sys.time())), "%Y%m%d")
# Today.Report = format(as.Date(as.POSIXlt(Sys.time())), "%A, %B %d, %Y")
source("scripts/colors.R")

This notebook

In this notebook we explore the files for the bulk RNAseq analyses and select the subset of data we need.

Background

Here we obtain data from the MR_CVD_MDD in plaques.

  • Genes.xlsx - list of genes of interest.
  • Variants.xlsx - list of variant(s) of interest.
library(openxlsx)

gene_list_df <- read.xlsx(paste0(TARGET_loc, "/targets.xlsx"), sheet = "Genes")

gene_list <- unlist(gene_list_df$Gene)
gene_list
 [1] "ADAP1"   "BAHD1"   "CHAF1A"  "DISP2"   "FAM98B"  "GNA11"   "GPR176"  "KNL1"    "MDFIC"   "MPND"    "NDUFA11" "PIP5K1C" "SUN1"    "TLE5"    "ZFAND2A"
variant_list <- read.xlsx(paste0(TARGET_loc, "/targets.xlsx"), sheet = "Variants")

DT::datatable(variant_list)
NA

Load data

First we will load the data:

  • prepared bulk RNA sequencing (RNAseq) experimental data from carotid plaques
  • Athero-Express clinical data.

Now you need to choose which of the datasets you will use for the downstream analyses.

  • raw
    • not transformed, raw counts
  • normalized data
    • normalized based on size factors based on estimateSizeFactors()
  • VST data
    • normalized based on size factors and log-transformed using vst()

Note: we advise using vst() transformed normalized data

Log-transformed normalized data

# AERNAScomboSE <- readRDS(file = paste0(OUT_loc, "/",Today,".AERNAScomboSEvst.CEA.1093pts.SE.after_qc.IC_academic.RDS"))
# AERNAScomboSE <- readRDS(file = paste0(OUT_loc, "/20240109.AERNAScomboSEvst.CEA.1093pts.SE.after_qc.IC_academic.RDS"))

AERNAScomboSE <- readRDS(file = paste0(OUT_loc, "/",Today,".AERNAS1SEvst.CEA.624pts.SE.after_qc.IC_academic.RDS"))

Clinical Data

First, we extract the clinical data.


bulkRNA_meta_clin <- as.tibble(colData(AERNAScomboSE))
bulkRNA_meta_clin %<>%
  # mutate(macrophages = factor(macrophages, levels = c("no staining", "minor staining", "moderate staining", "heavy staining"))) %>%
  # mutate(smc = factor(smc, levels = c("no staining", "minor staining", "moderate staining", "heavy staining"))) %>%
  # mutate(calcification = factor(calcification, levels = c("no staining", "minor staining", "moderate staining", "heavy staining"))) %>%
  # mutate(collagen = factor(collagen, levels = c("no staining", "minor staining", "moderate staining", "heavy staining"))) %>%
  # mutate(fat = factor(fat, levels = c("no fat", "< 40% fat", "> 40% fat"))) %>%
  mutate(study_number_row = STUDY_NUMBER) %>%
  as.data.frame() %>%
  column_to_rownames("study_number_row")
mutate: new variable 'study_number_row' (character) with 624 unique values and 0% NA
names(bulkRNA_meta_clin)[names(bulkRNA_meta_clin) == "STUDY_NUMBER"] <- "study_number"
head(bulkRNA_meta_clin)
dim(bulkRNA_meta_clin)
[1] 624  69

Second, we define the variables we need.


# Baseline table variables
basetable_vars = c("Hospital", "ORyear", "Artery_summary",
                   "Age", "Gender",
                   # "TC_finalCU", "LDL_finalCU", "HDL_finalCU", "TG_finalCU",
                   "TC_final", "LDL_final", "HDL_final", "TG_final",
                   # "hsCRP_plasma",
                   "systolic", "diastoli", "GFR_MDRD", "BMI",
                   "KDOQI", "BMI_WHO",
                   "SmokerStatus", "AlcoholUse",
                   "DiabetesStatus",
                   "Hypertension.selfreport", "Hypertension.selfreportdrug", "Hypertension.composite", "Hypertension.drugs",
                   "Med.anticoagulants", "Med.all.antiplatelet", "Med.Statin.LLD",
                   "Stroke_Dx", "sympt", "Symptoms.5G", "AsymptSympt", "AsymptSympt2G",
                   "Symptoms.Update2G", "Symptoms.Update3G",
                   "restenos", "stenose", "Artery_summary",
                   "CAD_history", "PAOD", "Peripheral.interv",
                   "EP_composite", "EP_composite_time", "epcom.3years", 
                   "EP_major", "EP_major_time","epmajor.3years",
                   "MAC_rankNorm", "SMC_rankNorm", "Macrophages.bin", "SMC.bin",
                   "Neutrophils_rankNorm", "MastCells_rankNorm",
                   "IPH.bin", "VesselDensity_rankNorm",
                   "Calc.bin", "Collagen.bin",
                   "Fat.bin_10", "Fat.bin_40",
                   "OverallPlaquePhenotype", "Plaque_Vulnerability_Index")

basetable_bin = c("Gender", "Artery_summary",
                  "KDOQI", "BMI_WHO",
                  "SmokerStatus", "AlcoholUse",
                  "DiabetesStatus",
                  "Hypertension.selfreport", "Hypertension.selfreportdrug", "Hypertension.composite", "Hypertension.drugs",
                  "Med.anticoagulants", "Med.all.antiplatelet", "Med.Statin.LLD",
                  "Stroke_Dx", "sympt", "Symptoms.5G", "AsymptSympt", "AsymptSympt2G",
                  "Symptoms.Update2G", "Symptoms.Update3G",
                  "restenos", "stenose", "Artery_summary",
                  "CAD_history", "PAOD", "Peripheral.interv",
                  "EP_composite", "Macrophages.bin", "SMC.bin",
                  "IPH.bin",
                  "Calc.bin", "Collagen.bin",
                  "Fat.bin_10", "Fat.bin_40",
                  "OverallPlaquePhenotype", "Plaque_Vulnerability_Index")
# basetable_bin

basetable_con = basetable_vars[!basetable_vars %in% basetable_bin]
# basetable_con

Expression differences

From here we can analyze whether specific genes differ between groups, or do this for the entire gene set as part of DE analysis, and then select our genes of interest.

From there, we extract the gene expression values, plus gene identifier, and select the genes of our interest.

expression_data <- assay(AERNAScomboSE)

# extract expression values from vsd, including ensembl names
expression_data <- as_tibble(data.frame(gene_ensembl = rowRanges(AERNAScomboSE)$feature_id, assay(AERNAScomboSE))) %>%
     mutate_at(vars(c("gene_ensembl")), list(as.character)) ## gene_ensembl needs to be character for annotation to work
mutate_at: no changes
# annotations
# gene symbol - via org.Hs.eg.db
# columns(org.Hs.eg.db)
expression_data$symbol <- mapIds(org.Hs.eg.db,
                    keys = expression_data$gene_ensembl,
                    column = "SYMBOL",
                    keytype = "ENSEMBL",
                    multiVals = "first")
'select()' returned 1:many mapping between keys and columns
# tidy and subset
expression_data_sel <- expression_data %>%
     dplyr::select(gene_ensembl, symbol, everything()) %>%
     # filter(symbol == "APOE" | symbol == "TRIB3") %>% # filter APOE and TRIB3
     dplyr::filter(symbol %in% gene_list)

head(expression_data_sel)

# tidy and subset non-selected genes
set.seed(141619)
expression_data_sample <- expression_data %>%
     dplyr::select(gene_ensembl, symbol, everything()) %>%
     sample_n(1000) %>%
     unite(symbol_ensembl, symbol, gene_ensembl, sep = "_", remove = FALSE)
sample_n: removed 20,835 rows (95%), 1,000 rows remaining
expression_data_sample_mean <- expression_data_sample %>%
  select_if(is.numeric) %>%
  colMeans() %>%
  as_tibble(rownames = "study_number") %>%
  dplyr::rename(expression_value_sample = value)
select_if: dropped 3 variables (symbol_ensembl, gene_ensembl, symbol)

Furthermore, the expression_data_sel df was gathered into a long form df for annotation with symptoms variables from the vsd object, and later visualization and statistics.

# gather expression_data_sel df into long df form for annotation, plotting and statistics
expression_long <-
     gather(expression_data_sel, key = "study_number", value = "expression_value", -c(gene_ensembl, symbol))
gather: reorganized (ae1, ae1026, ae1029, ae1032, ae1035, …) into (study_number, expression_value) [was 15x626, now 9360x4]
# old school way
# Annotate with smoking variables
# sample_ids <- expression_long$study_number
# mm <- match(expression_long$study_number, rownames(colData(vsd)))
#
# ## Add traits to df
# ## Binary traits
# expression_long$sex <- colData(vsd)$sex[mm]
# expression_long$testosterone <- colData(vsd)$testosterone[mm]
# expression_long$t_e2_ratio <- colData(vsd)$t_e2_ratio[mm]

# new school way
plaque_phenotypes_cat <- c("Macrophages.bin",
                           "SMC.bin",
                           "Calc.bin",
                           "Collagen.bin",
                           "Fat.bin_10", 
                           # "Fat.bin_40",
                           "IPH.bin")

plaque_phenotypes_num <- c("MAC_rankNorm", #"macmean0",
                           "SMC_rankNorm", #"smcmean0",
                           # "MastCells_rankNorm", #"mast_cells_plaque",
                           # "Neutrophils_rankNorm", #"neutrophils",
                           "VesselDensity_rankNorm")

expression_long <- expression_long %>%
  left_join(bulkRNA_meta_clin %>% dplyr::select(study_number,
                                       plaque_phenotypes_cat,
                                       plaque_phenotypes_num,
                                       epmajor.3years, 
                                       #epmajor.30days,
                                       AsymptSympt2G,
                                       Gender, Hospital, StudyName),
            by = "study_number") %>%
  mutate(epmajor_3years_yn = str_replace_all(epmajor.3years, c("Excluded" = "yes", "Included" = "no"))) #%>%
Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
Please use `all_of()` or `any_of()` instead.
# Was:
data %>% select(plaque_phenotypes_cat)

# Now:
data %>% select(all_of(plaque_phenotypes_cat))

See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
Please use `all_of()` or `any_of()` instead.
# Was:
data %>% select(plaque_phenotypes_num)

# Now:
data %>% select(all_of(plaque_phenotypes_num))

See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.left_join: added 14 columns (Macrophages.bin, SMC.bin, Calc.bin, Collagen.bin, Fat.bin_10, …)           > rows only in x                              0           > rows only in bulkRNA_meta_clin %>% d.. (    0)           > matched rows                            9,360           >                                        =======           > rows total                              9,360mutate: new variable 'epmajor_3years_yn' (character) with 3 unique values and 1% NA
  # mutate(epmajor.30days_yn = str_replace_all(epmajor.30days, c("Excluded" = "yes", "Included" = "no")))

head(expression_long)

# expression_long %>%
#   write_tsv("genes_interest_expression.txt")

Gene expression - distribution

Filter genes

In case some genes are not available in our data we could filter them here.

gene_list
 [1] "ADAP1"   "BAHD1"   "CHAF1A"  "DISP2"   "FAM98B"  "GNA11"   "GPR176"  "KNL1"    "MDFIC"   "MPND"    "NDUFA11" "PIP5K1C" "SUN1"    "TLE5"    "ZFAND2A"

This code is just an example to filter the list from genes that are not in the data.

  • COL3A ==> not found
  • COL2A ==> not found
gene_list_rm <- c("COL3A", "COL2A") 

temp = gene_list[!gene_list %in% gene_list_rm]

gene_list_qc <- c(temp)

# gene_list_qc <- gene_list
# 
# for debug
# gene_list_qc_replace <- c("MRTFA")

Plotting expression

Figure 1: Expression of genes of interest: boxplots

# Make directory for plots
ifelse(!dir.exists(file.path(QC_loc, "/Boxplots")), 
       dir.create(file.path(QC_loc, "/Boxplots")), 
       FALSE)
[1] FALSE
BOX_loc = paste0(QC_loc,"/Boxplots")

for(GENE in gene_list_qc){
  cat(paste0("Plotting expression for ", GENE,".\n"))
  temp <- subset(expression_long, symbol == GENE)
  
  compare_means(expression_value ~ Gender, data = temp)
  p1 <- ggpubr::ggboxplot(temp,
                          x = "Gender",
                          y = "expression_value",
                          color = "Gender",
                          palette = "npg",
                          add = "jitter",
                          ylab = paste0("normalized expression ", GENE,"" ),
                          repel = TRUE
                          ) + stat_compare_means()
  print(p1)
  cat(paste0("Saving image for ", GENE,".\n"))
  
  ggsave(filename = paste0(BOX_loc, "/", Today, ".",GENE,".expression_vs_gender.png"), plot = last_plot())
  ggsave(filename = paste0(BOX_loc, "/", Today, ".",GENE,".expression_vs_gender.pdf"), plot = last_plot())
  ggsave(filename = paste0(BOX_loc, "/", Today, ".",GENE,".expression_vs_gender.ps"), plot = last_plot())

  
  rm(temp, p1)
}
Plotting expression for ADAP1.
Saving image for ADAP1.
Plotting expression for BAHD1.
Saving image for BAHD1.
Plotting expression for CHAF1A.
Saving image for CHAF1A.
Plotting expression for DISP2.
Saving image for DISP2.
Plotting expression for FAM98B.
Saving image for FAM98B.
Plotting expression for GNA11.
Saving image for GNA11.
Plotting expression for GPR176.
Saving image for GPR176.
Plotting expression for KNL1.
Saving image for KNL1.
Plotting expression for MDFIC.
Saving image for MDFIC.
Plotting expression for MPND.
Saving image for MPND.
Plotting expression for NDUFA11.
Saving image for NDUFA11.
Plotting expression for PIP5K1C.
Saving image for PIP5K1C.
Plotting expression for SUN1.
Saving image for SUN1.
Plotting expression for TLE5.
Saving image for TLE5.
Plotting expression for ZFAND2A.
Saving image for ZFAND2A.

Figure 2A: Expression of genes of interest: histograms

# Make directory for plots
ifelse(!dir.exists(file.path(QC_loc, "/Histograms")), 
       dir.create(file.path(QC_loc, "/Histograms")), 
       FALSE)
[1] TRUE
HISTOGRAM_loc = paste0(QC_loc,"/Histograms")

for(GENE in gene_list_qc){
  # cat(paste0("Plotting expression for ", GENE,".\n"))
  temp <- subset(expression_long, symbol == GENE)
  p1 <- ggpubr::gghistogram(temp,
                          x = "expression_value",
                          y = "..count..",
                          color = "Gender", fill = "Gender",
                          palette = "npg",
                          add = "median",
                          ylab = paste0("normalized expression ", GENE,"" )  
                          )
  print(p1)
  cat(paste0("Saving image for ", GENE,".\n"))
  ggsave(filename = paste0(HISTOGRAM_loc, "/", Today, ".",GENE,".distribution.png"), plot = last_plot())
  ggsave(filename = paste0(HISTOGRAM_loc, "/", Today, ".",GENE,".distribution.pdf"), plot = last_plot())
  ggsave(filename = paste0(HISTOGRAM_loc, "/", Today, ".",GENE,".distribution.ps"), plot = last_plot())

  rm(temp, p1 )
}
Saving image for ADAP1.
Saving image for BAHD1.
Saving image for CHAF1A.
Saving image for DISP2.
Saving image for FAM98B.
Saving image for GNA11.
Saving image for GPR176.
Saving image for KNL1.
Saving image for MDFIC.
Saving image for MPND.
Saving image for NDUFA11.
Saving image for PIP5K1C.
Saving image for SUN1.
Saving image for TLE5.
Saving image for ZFAND2A.

Figure 2B: Expression of genes of interest: density plots

# Make directory for plots
ifelse(!dir.exists(file.path(QC_loc, "/Density")), 
       dir.create(file.path(QC_loc, "/Density")), 
       FALSE)
[1] TRUE
DENSITY_loc = paste0(QC_loc,"/Density")

for(GENE in gene_list_qc){
  # cat(paste0("Plotting expression for ", GENE,".\n"))
  temp <- subset(expression_long, symbol == GENE)
  p1 <- ggpubr::gghistogram(temp,
                          x = "expression_value",
                          y = "..density..",
                          color = "Gender", fill = "Gender",
                          palette = "npg",
                          add = "median",
                          ylab = paste0("normalized expression ", GENE,"" )  
                          )
  print(p1)
  cat(paste0("Saving image for ", GENE,".\n"))
  ggsave(filename = paste0(DENSITY_loc, "/", Today, ".",GENE,".density.png"), plot = last_plot())
  ggsave(filename = paste0(DENSITY_loc, "/", Today, ".",GENE,".density.pdf"), plot = last_plot())
  ggsave(filename = paste0(DENSITY_loc, "/", Today, ".",GENE,".density.ps"), plot = last_plot())
  
  rm(temp, p1 )
}
Saving image for ADAP1.
Saving image for BAHD1.
Saving image for CHAF1A.
Saving image for DISP2.
Saving image for FAM98B.
Saving image for GNA11.
Saving image for GPR176.
Saving image for KNL1.
Saving image for MDFIC.
Saving image for MPND.
Saving image for NDUFA11.
Saving image for PIP5K1C.
Saving image for SUN1.
Saving image for TLE5.
Saving image for ZFAND2A.

Compare expression to the expression of a sample of 1,000 genes

Figure 3: comparing expression of genes of interest to mean expression of a sample of 1,000 random genes


expression_wide <- expression_long %>%
  tidyr::unite("symbol_ensembl", symbol:gene_ensembl, remove = TRUE, sep = "_") %>%
  # dplyr::select(-gene_ensembl, -symbol) %>%
  tidyr::spread(key = symbol_ensembl, value = expression_value) 
# the next 3 lines of code gave an error when selecting for genes_interest, since one of the genes of interest is missing: FGF3 is not in the data set. So, we need to select for the other 15 genes.

temp <- expression_long %>%
  tidyr::unite("symbol_ensembl", symbol:gene_ensembl, remove = TRUE, sep = "_") %>%
  dplyr::select(symbol_ensembl)
temp <- temp %>% 
  tidyr::separate(symbol_ensembl, c("symbol", "gene_ensembl"), remove = FALSE) %>%
  dplyr::distinct(., symbol_ensembl, .keep_all = TRUE)

symbol_ensembl_gene_list_qc <- temp[temp$symbol %in% gene_list_qc,]$symbol_ensembl
expression_wide2 <- expression_wide %>%
  left_join(expression_data_sample_mean, by = "study_number") %>%
  dplyr::select(study_number, StudyName, symbol_ensembl_gene_list_qc, expression_value_sample)
left_join: added one column (expression_value_sample)           > rows only in x                            0           > rows only in expression_data_sample_.. (  0)           > matched rows                            624           >                                        =====           > rows total                              624Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
Please use `all_of()` or `any_of()` instead.
# Was:
data %>% select(symbol_ensembl_gene_list_qc)

# Now:
data %>% select(all_of(symbol_ensembl_gene_list_qc))

See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
expression_long2 <- expression_wide2 %>%
  gather(gene, expression_value, -study_number, -StudyName) %>%
  mutate(gene = str_replace_all(gene, c("expression_value_sample" = "Random genes"))) #%>%
gather: reorganized (MPND_ENSG00000008382, GNA11_ENSG00000088256, TLE5_ENSG00000104964, ADAP1_ENSG00000105963, MDFIC_ENSG00000135272, …) into (gene, expression_value) [was 624x18, now 9984x4]mutate: changed 624 values (6%) of 'gene' (0 new NAs)
  # mutate(gene = factor(gene, levels = c("Random genes", gene_list_qc)))
expression_long2
mean_1000_genes <- mean(expression_data_sample_mean$expression_value_sample)
# head(expression_long2)
# 

  p1 <- ggpubr::ggboxplot(expression_long2,
                          x = "gene",
                          y = "expression_value",
                          color = uithof_color[16],
                          add = "jitter",
                          add.params = list(size = 3, jitter = 0.3), 
                          ylab = paste0("normalized expression ")
                          ) +
    geom_hline(yintercept = mean_1000_genes, linetype = "dashed", color = uithof_color[26], size = 0.4) + 
    theme(axis.text.x = element_text(size = 10, angle = 45, hjust = 1, vjust = 1), # change orientation of x-axis labels
          axis.text.y = element_text(size = 12),
          axis.title.x = element_text(size = 14),
          axis.title.y = element_text(size = 14)) 
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.
  p1
  
  ggsave(filename = paste0(PLOT_loc, "/", Today, ".TargetExpression_vs_1000genes.png"), plot = last_plot())
Saving 7.29 x 4.51 in image
  ggsave(filename = paste0(PLOT_loc, "/", Today, ".TargetExpression_vs_1000genes.pdf"), plot = last_plot())
Saving 7.29 x 4.51 in image
  ggsave(filename = paste0(PLOT_loc, "/", Today, ".TargetExpression_vs_1000genes.ps"), plot = last_plot())
Saving 7.29 x 4.51 in image

  rm(p1, temp )

Heatmaps for genes of interest

If we would put these correlations in one simple and comprehensible figure, we could use a correlation heatmap. Again, correlation coefficients used here are Spearman’s.

Figure 4: correlation heatmap between expression of genes of interest

library(tidyverse)
library(magrittr)

temp <- expression_wide %>%
  column_to_rownames("study_number") %>%
  dplyr::select(symbol_ensembl_gene_list_qc) %>% 
  drop_na() %>% # drop NA 
  Filter(function(x) sd(x) != 0, .) # filter variables with sd = 0

temp.cor <- cor(temp, method = "spearman") 

p1 <- pheatmap(data.matrix(temp.cor), 
               scale = "none",
               cluster_rows = TRUE, 
               cluster_cols = TRUE,
               legend = TRUE,
               fontsize = 10)
p1


ggsave(filename = paste0(PLOT_loc, "/", Today, ".correlations.gene_list.pdf"), plot = p1, height = 15, width = 15)

ggsave(filename = paste0(PLOT_loc, "/", Today, ".correlations.gene_list.png"), plot = p1, height = 15, width = 15)


rm(temp, temp.cor, p1)

Gene target list

We are saving the final list of genes of interest


temp <- subset(expression_data_sel, select = c("gene_ensembl", "symbol"))

fwrite(temp,
       file = paste0(OUT_loc, "/", Today, ".target_list.qc.txt"),
       sep = " ", row.names = FALSE, col.names = TRUE,
       showProgress = TRUE)

Saving AERNA data subset

We will create a list of samples that should be included based on CEA, and having the proper informed consent (‘academic’). We will save the SummarizedExperiment as a RDS file for easy loading. The clinical data will also be saved as a separate txt-file.

To this end you need to lookup the EnsemblID (see above) for your target(s).

# targets = c("ENSG00000166033", # target
#             "ENSG00000169174") # positive control PCSK9
# targets = c("ENSG00000169174") # target/positive control PCSK9

targets = unlist(temp$gene_ensembl)

rm(temp)

Create a SummarizedExperiment

We make a SummarizedExperiment for the subset of RNAseq data. We make sure to only include the samples we need based on informed consent and we include only the requested variables.

Next, we are constructing the SummarizedExperiment.


AERNAS_meta_data = c("SampleType", "RNAseqTech", "RNAseqType", "RNAseqQC",
                     "StudyType", "StudyName", "StudyBiobank", "SampleSize")

cat("\n* making a SummarizedExperiment ...\n")

* making a SummarizedExperiment ...
# this is all the data passing RNAseq quality control and UMI-corrected
# - after filtering on informed consent and artery type, the end sample size should be 1093
# - after filtering on 'no commercial business' based on informed consent, there are fewer samples: yyyy
cat("  > getting counts\n")
  > getting counts
bulkRNA_countsFilt <- as.data.frame(assay(AERNAScomboSE[targets,]))
dim(bulkRNA_countsFilt)
[1]  15 624
head(bulkRNA_countsFilt)

cat("  > meta data and clinical data\n")
  > meta data and clinical data
# bulkRNA_meta_clin_COMMERCIAL <- subset(bulkRNA_meta_clin, select = c("study_number", basetable_vars))
bulkRNA_meta_clin_ACADEMIC <- subset(bulkRNA_meta_clin, select = c("study_number", 
                                                                   AERNAS_meta_data, # meta data of RNAseq experiment
                                                                   basetable_vars)) # selection of variables
dim(bulkRNA_meta_clin_ACADEMIC)
[1] 624  67
head(bulkRNA_meta_clin_ACADEMIC)

cat("  > rowRanges\n")
  > rowRanges
# bulkRNA_meta_clin_COMMERCIAL <- subset(bulkRNA_meta_clin, select = c("study_number", basetable_vars))
bulkRNA_rowRanges <- rowRanges(AERNAScomboSE[targets])
bulkRNA_rowRanges
GRanges object with 15 ranges and 2 metadata columns:
                  seqnames              ranges strand |      feature_id      symbol
                     <Rle>           <IRanges>  <Rle> |     <character> <character>
  ENSG00000008382       19     4343527-4360086      + | ENSG00000008382        MPND
  ENSG00000088256       19     3094362-3123999      + | ENSG00000088256       GNA11
  ENSG00000104964       19     3052910-3063107      - | ENSG00000104964        TLE5
  ENSG00000105963        7       897900-955407      - | ENSG00000105963       ADAP1
  ENSG00000135272        7 114922094-115019917      + | ENSG00000135272       MDFIC
              ...      ...                 ...    ... .             ...         ...
  ENSG00000167670       19     4402640-4445018      + | ENSG00000167670      CHAF1A
  ENSG00000171262       15   38454127-38487710      + | ENSG00000171262      FAM98B
  ENSG00000174886       19     5891276-5904006      - | ENSG00000174886     NDUFA11
  ENSG00000178381        7     1152071-1160759      - | ENSG00000178381     ZFAND2A
  ENSG00000186111       19     3630183-3700468      - | ENSG00000186111     PIP5K1C
  -------
  seqinfo: 331 sequences from an unspecified genome; no seqlengths
cat("  > construction of the SE\n")
  > construction of the SE
(AERNAScomboSE_target <- SummarizedExperiment(assays = list(counts = as.matrix(bulkRNA_countsFilt)),
                                              colData = bulkRNA_meta_clin_ACADEMIC,
                                              rowRanges = bulkRNA_rowRanges,
                                              metadata = "Athero-Express Biobank Study bulk RNA sequencing. Sample type: carotid plaques. Technology: CEL2-seq adapted for bulk RNA sequencing, thus 3'-focused. UMI-corrected. VST and size factor normalized. Target subset."))
class: RangedSummarizedExperiment 
dim: 15 624 
metadata(1): ''
assays(1): counts
rownames(15): ENSG00000008382 ENSG00000088256 ... ENSG00000178381 ENSG00000186111
rowData names(2): feature_id symbol
colnames(624): ae1 ae1026 ... ae998 ae999
colData names(67): study_number SampleType ... OverallPlaquePhenotype Plaque_Vulnerability_Index
cat("\n* removing intermediate files ...\n")

* removing intermediate files ...
rm(bulkRNA_meta_clin_ACADEMIC, bulkRNA_countsFilt, bulkRNA_rowRanges)

Saving data subset

Sample list and clinical data.

temp <- as.tibble(subset(colData(AERNAScomboSE_target), select = c("study_number", AERNAS_meta_data)))

fwrite(temp,
       file = paste0(OUT_loc, "/", Today, ".AERNAS1SE_target.CEA.624pts.samplelist.after_qc.IC_academic.csv"),
       sep = ",", row.names = FALSE, col.names = TRUE,
       showProgress = TRUE)
rm(temp)

temp <- as.tibble(subset(colData(AERNAScomboSE_target), select = c("study_number", basetable_vars)))

fwrite(temp,
       file = paste0(OUT_loc, "/", Today, ".AERNAS1SE_target.CEA.624pts.clinicaldata.after_qc.IC_academic.csv"),
       sep = ",", row.names = FALSE, col.names = TRUE,
       showProgress = TRUE)
rm(temp)

Assay data and gene information.

temp <- as_tibble(assay(AERNAScomboSE_target))

fwrite(temp,
       file = paste0(OUT_loc, "/", Today, ".AERNAS1SE_target.CEA.624pts.assay.after_qc.IC_academic.csv"),
       sep = ",", row.names = FALSE, col.names = TRUE,
       showProgress = TRUE)
rm(temp)

temp <- as_tibble(rowRanges(AERNAScomboSE_target))

fwrite(temp,
       file = paste0(OUT_loc, "/", Today, ".AERNAS1SE_target.CEA.624pts.genedata.after_qc.IC_academic.csv"),
       sep = ",", row.names = FALSE, col.names = TRUE,
       showProgress = TRUE)
rm(temp)

The subset as SummarizedExperiment() dataset in RDS-format.


# saveRDS(AERNASE, file = paste0(OUT_loc, "/", Today, ".AERNAScomboSE_target.CEA.608pts.SE.after_qc.IC_commercial.RDS"))
saveRDS(AERNAScomboSE_target, file = paste0(OUT_loc, "/", Today, ".AERNAS1SE_target.CEA.624pts.SE.after_qc.IC_academic.RDS"))

Session information


Version:      v1.0.1
Last update:  2025-03-28
Written by:   Sander W. van der Laan (s.w.vanderlaan-2[at]umcutrecht.nl).
Description:  Script to load bulk RNA sequencing data, and perform gene expression analyses, and visualisations.
Minimum requirements: R version 3.5.2 (2018-12-20) -- 'Eggshell Igloo', macOS Mojave (10.14.2).

**MoSCoW To-Do List**
The things we Must, Should, Could, and Would have given the time we have.
_M_

_S_

_C_

_W_

**Changes log**
* v1.0.1 Updated the script to include the latest data and to explore the subset of data.
* v1.0.0 Inital version. Re-arranged to explore the subset of data. 

sessionInfo()
R version 4.4.3 (2025-02-28)
Platform: x86_64-apple-darwin20
Running under: macOS Sequoia 15.4

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/Amsterdam
tzcode source: internal

attached base packages:
 [1] stats4    grid      tools     stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] magrittr_2.0.3                          annotables_0.2.0                        EnhancedVolcano_1.22.0                  ggrepel_0.9.6                           EnsDb.Hsapiens.v86_2.99.0              
 [6] ensembldb_2.28.1                        AnnotationFilter_1.28.0                 TxDb.Hsapiens.UCSC.hg19.knownGene_3.2.2 mygene_1.40.0                           txdbmaker_1.0.1                        
[11] org.Hs.eg.db_3.19.1                     DESeq2_1.44.0                           SummarizedExperiment_1.34.0             MatrixGenerics_1.16.0                   matrixStats_1.4.1                      
[16] GenomicFeatures_1.56.0                  AnnotationDbi_1.66.0                    Biobase_2.64.0                          GenomicRanges_1.56.2                    GenomeInfoDb_1.40.1                    
[21] IRanges_2.38.1                          S4Vectors_0.42.1                        BiocGenerics_0.50.0                     Hmisc_5.1-3                             survminer_0.4.9                        
[26] survival_3.8-3                          GGally_2.2.1                            PerformanceAnalytics_2.0.4              xts_0.14.0                              zoo_1.8-12                             
[31] ggcorrplot_0.1.4.999                    corrr_0.4.4                             reshape2_1.4.4                          bacon_1.32.0                            ellipse_0.5.0                          
[36] BiocParallel_1.38.0                     meta_7.0-0                              metadat_1.2-0                           qqman_0.1.9                             tidylog_1.1.0                          
[41] gridExtra_2.3                           plyr_1.8.9                              rmarkdown_2.28                          officer_0.6.7                           flextable_0.9.7                        
[46] writexl_1.5.1                           patchwork_1.3.0.9000                    labelled_2.13.0                         sjPlot_2.8.16                           UpSetR_1.4.0                           
[51] ggpubr_0.6.0.999                        forestplot_3.1.5                        abind_1.4-8                             checkmate_2.3.2                         pheatmap_1.0.12                        
[56] devtools_2.4.5                          usethis_3.0.0                           BlandAltmanLeh_0.3.1                    tableone_0.13.2                         openxlsx_4.2.7.1                       
[61] haven_2.5.4                             eeptools_1.2.5                          DT_0.33                                 knitr_1.48                              lubridate_1.9.3                        
[66] forcats_1.0.0                           stringr_1.5.1                           purrr_1.0.2                             tibble_3.2.1                            ggplot2_3.5.1                          
[71] tidyverse_2.0.0                         data.table_1.16.2                       naniar_1.1.0                            tidyr_1.3.1                             dplyr_1.1.4                            
[76] optparse_1.7.5                          readr_2.1.5                             pander_0.6.5                            R.utils_2.12.3                          R.oo_1.26.0                            
[81] R.methodsS3_1.8.2                       worcs_0.1.15                            credentials_2.0.2                      

loaded via a namespace (and not attached):
  [1] progress_1.2.3           sjmisc_2.8.10            urlchecker_1.0.1         nnet_7.3-20              Biostrings_2.72.1        katex_1.5.0              vctrs_0.6.5              rticles_0.27            
  [9] digest_0.6.37            png_0.1-8                proxy_0.4-27             renv_1.0.11              MASS_7.3-64              fontLiberation_0.1.0     httpuv_1.6.15            withr_3.0.2             
 [17] xfun_0.48                ellipsis_0.3.2           memoise_2.0.1            ggsci_3.2.0              profvis_0.4.0            calibrate_1.7.7          systemfonts_1.1.0        ragg_1.3.3              
 [25] V8_6.0.0                 prettyunits_1.2.0        Formula_1.2-5            sys_3.4.3                datawizard_0.13.0        KEGGREST_1.44.1          promises_1.3.0           httr_1.4.7              
 [33] rstatix_0.7.2            restfulr_0.0.15          rstudioapi_0.16.0        UCSC.utils_1.0.0         miniUI_0.1.1.1           generics_0.1.3           base64enc_0.1-3          curl_5.2.3              
 [41] mitools_2.4              zlibbioc_1.50.0          ggeffects_1.7.2          GenomeInfoDbData_1.2.12  quadprog_1.5-8           SparseArray_1.4.8        xtable_1.8-4             evaluate_1.0.1          
 [49] S4Arrays_1.4.1           BiocFileCache_2.12.0     hms_1.1.3                filelock_1.0.3           colorspace_2.1-1         getopt_1.20.4            lmtest_0.9-40            later_1.3.2             
 [57] lattice_0.22-6           XML_3.99-0.17            survey_4.4-2             class_7.3-23             pillar_1.10.1            nlme_3.1-167             performance_0.12.3       compiler_4.4.3          
 [65] stringi_1.8.4            minqa_1.2.8              GenomicAlignments_1.40.0 crayon_1.5.3             BiocIO_1.14.0            chron_2.3-61             locfit_1.5-9.10          bit_4.5.0               
 [73] mathjaxr_1.6-0           codetools_0.2-20         textshaping_0.4.0        clisymbols_1.2.0         openssl_2.2.2            crosstalk_1.2.1          bslib_0.8.0              e1071_1.7-16            
 [81] mime_0.12                splines_4.4.3            Rcpp_1.0.13              dbplyr_2.5.0             blob_1.2.4               lme4_1.1-35.5            fs_1.6.4                 prereg_0.6.0            
 [89] pkgbuild_1.4.4           gh_1.4.1                 ggsignif_0.6.4           sqldf_0.4-11             Matrix_1.7-2             tzdb_0.4.0               visdat_0.6.0             pkgconfig_2.0.3         
 [97] equatags_0.2.1           cachem_1.1.0             RSQLite_2.3.7            DBI_1.2.3                numDeriv_2016.8-1.1      fastmap_1.2.0            scales_1.3.0             Rsamtools_2.20.0        
[105] broom_1.0.7              sass_0.4.9               coda_0.19-4.1            ggstats_0.7.0            insight_0.20.5           carData_3.0-5            rpart_4.1.24             farver_2.1.2            
[113] gsubfn_0.7               yaml_2.3.10              foreign_0.8-88           sjstats_0.19.0           rtracklayer_1.64.0       cli_3.6.4                lifecycle_1.0.4          rsconnect_1.3.1         
[121] askpass_1.2.1            sessioninfo_1.2.2        backports_1.5.0          timechange_0.3.0         gtable_0.3.6             rjson_0.2.23             metafor_4.6-0            parallel_4.4.3          
[129] jsonlite_1.8.9           bitops_1.0-9             bit64_4.5.2              proto_1.0.0              zip_2.3.1                ranger_0.16.0            jquerylib_0.1.4          survMisc_0.5.6          
[137] lazyeval_0.2.2           shiny_1.9.1              xslt_1.4.6               htmltools_0.5.8.1        KMsurv_0.1-5             rappdirs_0.3.3           sjlabelled_1.2.0         tinytex_0.53            
[145] glue_1.8.0               httr2_1.0.5              XVector_0.44.0           gdtools_0.4.0            RCurl_1.98-1.16          boot_1.3-31              R6_2.6.1                 arm_1.14-4              
[153] km.ci_0.5-6              vcd_1.4-13               CompQuadForm_1.4.3       labeling_0.4.3           cluster_2.1.8            pkgload_1.4.0            nloptr_2.1.1             ProtGenerics_1.36.0     
[161] DelayedArray_0.30.1      tidyselect_1.2.1         htmlTable_2.4.3          xml2_1.3.6               fontBitstreamVera_0.1.1  car_3.1-3                munsell_0.5.1            fontquiver_0.2.1        
[169] htmlwidgets_1.6.4        RColorBrewer_1.1-3       biomaRt_2.60.1           rlang_1.1.5              gert_2.1.4               uuid_1.2-1               remotes_2.5.0           

Saving environment

save.image(paste0(PROJECT_loc, "/",Today,".",PROJECTNAME,".bulkRNAseq.exploration.RData"))
© 1979-2025 Sander W. van der Laan | s.w.vanderlaan[at]gmail[dot]com | vanderlaanand.science.
LS0tCnRpdGxlOiAiRXhwbG9yYXRpb24gYnVsa1JOQXNlcSBhbmFseXNlcyIKc3VidGl0bGU6IEFjY29tcGFueWluZyAnTVJfQ1ZEX01ERCcKYXV0aG9yOiAnW1NhbmRlciBXLiB2YW4gZGVyIExhYW4sIFBoRF0oaHR0cHM6Ly92YW5kZXJsYWFuYW5kLnNjaWVuY2UpIHwgcy53LnZhbmRlcmxhYW5bYXRdZ21haWxbZG90XWNvbScKZGF0ZTogJ2ByIFN5cy5EYXRlKClgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICBjYWNoZTogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvbGxhcHNlOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnLmFsaWduOiBjZW50ZXIKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGZpZ19oZWlnaHQ6IDEwCiAgICBmaWdfcmV0aW5hOiAyCiAgICBmaWdfd2lkdGg6IDEyCiAgICB0aGVtZTogcGFwZXIKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogbm8KICAgICAgc21vb3RoX3Njcm9sbDogeWVzCiAgICBoaWdobGlnaHQ6IHRhbmdvCm1haW5mb250OiBIZWx2ZXRpY2EKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCmtuaXQ6IHdvcmNzOjpjaXRlX2FsbAotLS0KCiMgR2VuZXJhbCBTZXR1cApgYGB7ciBlY2hvID0gRkFMU0V9CiMgcm0obGlzdCA9IGxzKCkpCmBgYAoKYGBge3IgTG9jYWxTeXN0ZW0sIGVjaG8gPSBGQUxTRX0Kc291cmNlKCJzY3JpcHRzL2xvY2FsLnN5c3RlbS5SIikKYGBgCgpgYGB7ciBTb3VyY2UgZnVuY3Rpb25zfQpzb3VyY2UoInNjcmlwdHMvZnVuY3Rpb25zLlIiKQpgYGAKCmBgYHtyIGxvYWRpbmdfcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNvdXJjZSgic2NyaXB0cy9wYWNrMDIucGFja2FnZXMuUiIpCmBgYAoKYGBge3IgU2V0dGluZzogQ29sb3JzfQojIFRvZGF5ID0gZm9ybWF0KGFzLkRhdGUoYXMuUE9TSVhsdChTeXMudGltZSgpKSksICIlWSVtJWQiKQojIFRvZGF5LlJlcG9ydCA9IGZvcm1hdChhcy5EYXRlKGFzLlBPU0lYbHQoU3lzLnRpbWUoKSkpLCAiJUEsICVCICVkLCAlWSIpCnNvdXJjZSgic2NyaXB0cy9jb2xvcnMuUiIpCmBgYAoKYGBge3Igc2V0dXBfbm90ZWJvb2ssIGluY2x1ZGU9RkFMU0V9CiMgV2UgcmVjb21tZW5kIHRoYXQgeW91IHByZXBhcmUgeW91ciByYXcgZGF0YSBmb3IgYW5hbHlzaXMgaW4gJ3ByZXBhcmVfZGF0YS5SJywKIyBhbmQgZW5kIHRoYXQgZmlsZSB3aXRoIGVpdGhlciBvcGVuX2RhdGEoeW91cmRhdGEpLCBvciBjbG9zZWRfZGF0YSh5b3VyZGF0YSkuCiMgVGhlbiwgdW5jb21tZW50IHRoZSBsaW5lIGJlbG93IHRvIGxvYWQgdGhlIG9yaWdpbmFsIG9yIHN5bnRoZXRpYyBkYXRhCiMgKHdoaWNoZXZlciBpcyBhdmFpbGFibGUpLCB0byBhbGxvdyBhbnlvbmUgdG8gcmVwcm9kdWNlIHlvdXIgY29kZToKIyBsb2FkX2RhdGEoKQoKIyBmdXJ0aGVyIGRlZmluZSBzb21lIGtuaXRyLW9wdGlvbnMuCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDgsIGZpZy5wYXRoID0gJ0ZpZ3VyZXMvJywgCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gVFJVRSwgIyBzaG93IHdhcm5pbmdzIGR1cmluZyBjb2RlYm9vayBnZW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gVFJVRSwgIyBzaG93IG1lc3NhZ2VzIGR1cmluZyBjb2RlYm9vayBnZW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgICAgICBlcnJvciA9IFRSVUUsICMgZG8gbm90IGludGVycnVwdCBjb2RlYm9vayBnZW5lcmF0aW9uIGluIGNhc2Ugb2YgZXJyb3JzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB1c3VhbGx5IGJldHRlciBmb3IgZGVidWdnaW5nCiAgICAgICAgICAgICAgICAgICAgICBlY2hvID0gVFJVRSwgICMgc2hvdyBSIGNvZGUKICAgICAgICAgICAgICAgICAgICAgIGV2YWwgPSBUUlVFKQoKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSkKIyBwYW5kZXI6OnBhbmRlck9wdGlvbnMoInRhYmxlLnNwbGl0LnRhYmxlIiwgSW5mKQpsaWJyYXJ5KCJ3b3JjcyIpCmxpYnJhcnkoInJtYXJrZG93biIpCmBgYAoKIyBUaGlzIG5vdGVib29rIAoKSW4gdGhpcyBub3RlYm9vayB3ZSBleHBsb3JlIHRoZSBmaWxlcyBmb3IgdGhlIGJ1bGsgUk5Bc2VxIGFuYWx5c2VzIGFuZCBzZWxlY3QgdGhlIHN1YnNldCBvZiBkYXRhIHdlIG5lZWQuIAoKCiMjIEJhY2tncm91bmQKCkhlcmUgd2Ugb2J0YWluIGRhdGEgZnJvbSB0aGUgYHIgVFJBSVRfT0ZfSU5URVJFU1RgIGluIHBsYXF1ZXMuCgotICAgYEdlbmVzLnhsc3hgIC0gbGlzdCBvZiBnZW5lcyBvZiBpbnRlcmVzdC4gCi0gICBgVmFyaWFudHMueGxzeGAgLSBsaXN0IG9mIHZhcmlhbnQocykgb2YgaW50ZXJlc3QuIAoKYGBge3IgdGFyZ2V0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShvcGVueGxzeCkKCmdlbmVfbGlzdF9kZiA8LSByZWFkLnhsc3gocGFzdGUwKFRBUkdFVF9sb2MsICIvdGFyZ2V0cy54bHN4IiksIHNoZWV0ID0gIkdlbmVzIikKCmdlbmVfbGlzdCA8LSB1bmxpc3QoZ2VuZV9saXN0X2RmJEdlbmUpCmdlbmVfbGlzdAoKdmFyaWFudF9saXN0IDwtIHJlYWQueGxzeChwYXN0ZTAoVEFSR0VUX2xvYywgIi90YXJnZXRzLnhsc3giKSwgc2hlZXQgPSAiVmFyaWFudHMiKQoKRFQ6OmRhdGF0YWJsZSh2YXJpYW50X2xpc3QpCgpgYGAKCgojIExvYWQgZGF0YQoKRmlyc3Qgd2Ugd2lsbCBsb2FkIHRoZSBkYXRhOgoKLSAgIHByZXBhcmVkIGJ1bGsgUk5BIHNlcXVlbmNpbmcgKFJOQXNlcSkgZXhwZXJpbWVudGFsIGRhdGEgZnJvbSBjYXJvdGlkIHBsYXF1ZXMKLSAgIEF0aGVyby1FeHByZXNzIGNsaW5pY2FsIGRhdGEuCgpOb3cgeW91IG5lZWQgdG8gY2hvb3NlIHdoaWNoIG9mIHRoZSBkYXRhc2V0cyB5b3Ugd2lsbCB1c2UgZm9yIHRoZSBkb3duc3RyZWFtIGFuYWx5c2VzLiAKCi0gKipyYXcqKgogIC0gbm90IHRyYW5zZm9ybWVkLCByYXcgY291bnRzCi0gKipub3JtYWxpemVkIGRhdGEqKgogIC0gbm9ybWFsaXplZCBiYXNlZCBvbiBzaXplIGZhY3RvcnMgYmFzZWQgb24gYGVzdGltYXRlU2l6ZUZhY3RvcnMoKWAKLSAqKlZTVCBkYXRhKioKICAtIG5vcm1hbGl6ZWQgYmFzZWQgb24gc2l6ZSBmYWN0b3JzIGFuZCBsb2ctdHJhbnNmb3JtZWQgdXNpbmcgYHZzdCgpYCAKCj4gTm90ZTogd2UgYWR2aXNlIHVzaW5nIGB2c3QoKWAgdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBkYXRhCgo8IS0tICMjIFJhdyBkYXRhIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gQUVSTkFTY29tYm9TRSA8LSByZWFkUkRTKGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8yMDI0MDEwOS5BRVJOQVNjb21ib1NFLkNFQS4xMDkzcHRzLlNFLmFmdGVyX3FjLklDX2FjYWRlbWljLlJEUyIpKSAtLT4KCjwhLS0gYGBgIC0tPgoKPCEtLSAjIyBOb3JtYWxpemVkIGRhdGEgLS0+CjwhLS0gYGBge3J9IC0tPgo8IS0tIEFFUk5BU2NvbWJvU0UgPC0gcmVhZFJEUyhmaWxlID0gcGFzdGUwKE9VVF9sb2MsICIvMjAyNDAxMDkuQUVSTkFTY29tYm9TRW5vcm0uQ0VBLjEwOTNwdHMuU0UuYWZ0ZXJfcWMuSUNfYWNhZGVtaWMuUkRTIikpIC0tPgoKPCEtLSBgYGAgLS0+CgojIyBMb2ctdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBkYXRhCmBgYHtyfQojIEFFUk5BU2NvbWJvU0UgPC0gcmVhZFJEUyhmaWxlID0gcGFzdGUwKE9VVF9sb2MsICIvIixUb2RheSwiLkFFUk5BU2NvbWJvU0V2c3QuQ0VBLjEwOTNwdHMuU0UuYWZ0ZXJfcWMuSUNfYWNhZGVtaWMuUkRTIikpCiMgQUVSTkFTY29tYm9TRSA8LSByZWFkUkRTKGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8yMDI0MDEwOS5BRVJOQVNjb21ib1NFdnN0LkNFQS4xMDkzcHRzLlNFLmFmdGVyX3FjLklDX2FjYWRlbWljLlJEUyIpKQoKQUVSTkFTY29tYm9TRSA8LSByZWFkUkRTKGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8iLFRvZGF5LCIuQUVSTkFTMVNFdnN0LkNFQS42MjRwdHMuU0UuYWZ0ZXJfcWMuSUNfYWNhZGVtaWMuUkRTIikpCgpgYGAKCgojIyBDbGluaWNhbCBEYXRhCgpGaXJzdCwgd2UgZXh0cmFjdCB0aGUgY2xpbmljYWwgZGF0YS4KYGBge3IgUGFyc2UgQ2xpbmljYWxEYXRhIFJOQXNlcX0KCmJ1bGtSTkFfbWV0YV9jbGluIDwtIGFzLnRpYmJsZShjb2xEYXRhKEFFUk5BU2NvbWJvU0UpKQpidWxrUk5BX21ldGFfY2xpbiAlPD4lCiAgIyBtdXRhdGUobWFjcm9waGFnZXMgPSBmYWN0b3IobWFjcm9waGFnZXMsIGxldmVscyA9IGMoIm5vIHN0YWluaW5nIiwgIm1pbm9yIHN0YWluaW5nIiwgIm1vZGVyYXRlIHN0YWluaW5nIiwgImhlYXZ5IHN0YWluaW5nIikpKSAlPiUKICAjIG11dGF0ZShzbWMgPSBmYWN0b3Ioc21jLCBsZXZlbHMgPSBjKCJubyBzdGFpbmluZyIsICJtaW5vciBzdGFpbmluZyIsICJtb2RlcmF0ZSBzdGFpbmluZyIsICJoZWF2eSBzdGFpbmluZyIpKSkgJT4lCiAgIyBtdXRhdGUoY2FsY2lmaWNhdGlvbiA9IGZhY3RvcihjYWxjaWZpY2F0aW9uLCBsZXZlbHMgPSBjKCJubyBzdGFpbmluZyIsICJtaW5vciBzdGFpbmluZyIsICJtb2RlcmF0ZSBzdGFpbmluZyIsICJoZWF2eSBzdGFpbmluZyIpKSkgJT4lCiAgIyBtdXRhdGUoY29sbGFnZW4gPSBmYWN0b3IoY29sbGFnZW4sIGxldmVscyA9IGMoIm5vIHN0YWluaW5nIiwgIm1pbm9yIHN0YWluaW5nIiwgIm1vZGVyYXRlIHN0YWluaW5nIiwgImhlYXZ5IHN0YWluaW5nIikpKSAlPiUKICAjIG11dGF0ZShmYXQgPSBmYWN0b3IoZmF0LCBsZXZlbHMgPSBjKCJubyBmYXQiLCAiPCA0MCUgZmF0IiwgIj4gNDAlIGZhdCIpKSkgJT4lCiAgbXV0YXRlKHN0dWR5X251bWJlcl9yb3cgPSBTVFVEWV9OVU1CRVIpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoInN0dWR5X251bWJlcl9yb3ciKQpuYW1lcyhidWxrUk5BX21ldGFfY2xpbilbbmFtZXMoYnVsa1JOQV9tZXRhX2NsaW4pID09ICJTVFVEWV9OVU1CRVIiXSA8LSAic3R1ZHlfbnVtYmVyIgpoZWFkKGJ1bGtSTkFfbWV0YV9jbGluKQpkaW0oYnVsa1JOQV9tZXRhX2NsaW4pCgpgYGAKCgpTZWNvbmQsIHdlIGRlZmluZSB0aGUgdmFyaWFibGVzIHdlIG5lZWQuCgpgYGB7cn0KCiMgQmFzZWxpbmUgdGFibGUgdmFyaWFibGVzCmJhc2V0YWJsZV92YXJzID0gYygiSG9zcGl0YWwiLCAiT1J5ZWFyIiwgIkFydGVyeV9zdW1tYXJ5IiwKICAgICAgICAgICAgICAgICAgICJBZ2UiLCAiR2VuZGVyIiwKICAgICAgICAgICAgICAgICAgICMgIlRDX2ZpbmFsQ1UiLCAiTERMX2ZpbmFsQ1UiLCAiSERMX2ZpbmFsQ1UiLCAiVEdfZmluYWxDVSIsCiAgICAgICAgICAgICAgICAgICAiVENfZmluYWwiLCAiTERMX2ZpbmFsIiwgIkhETF9maW5hbCIsICJUR19maW5hbCIsCiAgICAgICAgICAgICAgICAgICAjICJoc0NSUF9wbGFzbWEiLAogICAgICAgICAgICAgICAgICAgInN5c3RvbGljIiwgImRpYXN0b2xpIiwgIkdGUl9NRFJEIiwgIkJNSSIsCiAgICAgICAgICAgICAgICAgICAiS0RPUUkiLCAiQk1JX1dITyIsCiAgICAgICAgICAgICAgICAgICAiU21va2VyU3RhdHVzIiwgIkFsY29ob2xVc2UiLAogICAgICAgICAgICAgICAgICAgIkRpYWJldGVzU3RhdHVzIiwKICAgICAgICAgICAgICAgICAgICJIeXBlcnRlbnNpb24uc2VsZnJlcG9ydCIsICJIeXBlcnRlbnNpb24uc2VsZnJlcG9ydGRydWciLCAiSHlwZXJ0ZW5zaW9uLmNvbXBvc2l0ZSIsICJIeXBlcnRlbnNpb24uZHJ1Z3MiLAogICAgICAgICAgICAgICAgICAgIk1lZC5hbnRpY29hZ3VsYW50cyIsICJNZWQuYWxsLmFudGlwbGF0ZWxldCIsICJNZWQuU3RhdGluLkxMRCIsCiAgICAgICAgICAgICAgICAgICAiU3Ryb2tlX0R4IiwgInN5bXB0IiwgIlN5bXB0b21zLjVHIiwgIkFzeW1wdFN5bXB0IiwgIkFzeW1wdFN5bXB0MkciLAogICAgICAgICAgICAgICAgICAgIlN5bXB0b21zLlVwZGF0ZTJHIiwgIlN5bXB0b21zLlVwZGF0ZTNHIiwKICAgICAgICAgICAgICAgICAgICJyZXN0ZW5vcyIsICJzdGVub3NlIiwgIkFydGVyeV9zdW1tYXJ5IiwKICAgICAgICAgICAgICAgICAgICJDQURfaGlzdG9yeSIsICJQQU9EIiwgIlBlcmlwaGVyYWwuaW50ZXJ2IiwKICAgICAgICAgICAgICAgICAgICJFUF9jb21wb3NpdGUiLCAiRVBfY29tcG9zaXRlX3RpbWUiLCAiZXBjb20uM3llYXJzIiwgCiAgICAgICAgICAgICAgICAgICAiRVBfbWFqb3IiLCAiRVBfbWFqb3JfdGltZSIsImVwbWFqb3IuM3llYXJzIiwKICAgICAgICAgICAgICAgICAgICJNQUNfcmFua05vcm0iLCAiU01DX3JhbmtOb3JtIiwgIk1hY3JvcGhhZ2VzLmJpbiIsICJTTUMuYmluIiwKICAgICAgICAgICAgICAgICAgICJOZXV0cm9waGlsc19yYW5rTm9ybSIsICJNYXN0Q2VsbHNfcmFua05vcm0iLAogICAgICAgICAgICAgICAgICAgIklQSC5iaW4iLCAiVmVzc2VsRGVuc2l0eV9yYW5rTm9ybSIsCiAgICAgICAgICAgICAgICAgICAiQ2FsYy5iaW4iLCAiQ29sbGFnZW4uYmluIiwKICAgICAgICAgICAgICAgICAgICJGYXQuYmluXzEwIiwgIkZhdC5iaW5fNDAiLAogICAgICAgICAgICAgICAgICAgIk92ZXJhbGxQbGFxdWVQaGVub3R5cGUiLCAiUGxhcXVlX1Z1bG5lcmFiaWxpdHlfSW5kZXgiKQoKYmFzZXRhYmxlX2JpbiA9IGMoIkdlbmRlciIsICJBcnRlcnlfc3VtbWFyeSIsCiAgICAgICAgICAgICAgICAgICJLRE9RSSIsICJCTUlfV0hPIiwKICAgICAgICAgICAgICAgICAgIlNtb2tlclN0YXR1cyIsICJBbGNvaG9sVXNlIiwKICAgICAgICAgICAgICAgICAgIkRpYWJldGVzU3RhdHVzIiwKICAgICAgICAgICAgICAgICAgIkh5cGVydGVuc2lvbi5zZWxmcmVwb3J0IiwgIkh5cGVydGVuc2lvbi5zZWxmcmVwb3J0ZHJ1ZyIsICJIeXBlcnRlbnNpb24uY29tcG9zaXRlIiwgIkh5cGVydGVuc2lvbi5kcnVncyIsCiAgICAgICAgICAgICAgICAgICJNZWQuYW50aWNvYWd1bGFudHMiLCAiTWVkLmFsbC5hbnRpcGxhdGVsZXQiLCAiTWVkLlN0YXRpbi5MTEQiLAogICAgICAgICAgICAgICAgICAiU3Ryb2tlX0R4IiwgInN5bXB0IiwgIlN5bXB0b21zLjVHIiwgIkFzeW1wdFN5bXB0IiwgIkFzeW1wdFN5bXB0MkciLAogICAgICAgICAgICAgICAgICAiU3ltcHRvbXMuVXBkYXRlMkciLCAiU3ltcHRvbXMuVXBkYXRlM0ciLAogICAgICAgICAgICAgICAgICAicmVzdGVub3MiLCAic3Rlbm9zZSIsICJBcnRlcnlfc3VtbWFyeSIsCiAgICAgICAgICAgICAgICAgICJDQURfaGlzdG9yeSIsICJQQU9EIiwgIlBlcmlwaGVyYWwuaW50ZXJ2IiwKICAgICAgICAgICAgICAgICAgIkVQX2NvbXBvc2l0ZSIsICJNYWNyb3BoYWdlcy5iaW4iLCAiU01DLmJpbiIsCiAgICAgICAgICAgICAgICAgICJJUEguYmluIiwKICAgICAgICAgICAgICAgICAgIkNhbGMuYmluIiwgIkNvbGxhZ2VuLmJpbiIsCiAgICAgICAgICAgICAgICAgICJGYXQuYmluXzEwIiwgIkZhdC5iaW5fNDAiLAogICAgICAgICAgICAgICAgICAiT3ZlcmFsbFBsYXF1ZVBoZW5vdHlwZSIsICJQbGFxdWVfVnVsbmVyYWJpbGl0eV9JbmRleCIpCiMgYmFzZXRhYmxlX2JpbgoKYmFzZXRhYmxlX2NvbiA9IGJhc2V0YWJsZV92YXJzWyFiYXNldGFibGVfdmFycyAlaW4lIGJhc2V0YWJsZV9iaW5dCiMgYmFzZXRhYmxlX2NvbgoKYGBgCgoKIyBFeHByZXNzaW9uIGRpZmZlcmVuY2VzCgpGcm9tIGhlcmUgd2UgY2FuIGFuYWx5emUgd2hldGhlciBzcGVjaWZpYyBnZW5lcyBkaWZmZXIgYmV0d2VlbiBncm91cHMsIG9yIGRvIHRoaXMgZm9yIHRoZSBlbnRpcmUgZ2VuZSBzZXQgYXMgcGFydCBvZiBERSBhbmFseXNpcywgYW5kIHRoZW4gc2VsZWN0IG91ciBnZW5lcyBvZiBpbnRlcmVzdC4gCgpGcm9tIHRoZXJlLCB3ZSBleHRyYWN0IHRoZSBnZW5lIGV4cHJlc3Npb24gdmFsdWVzLCBwbHVzIGdlbmUgaWRlbnRpZmllciwgYW5kIHNlbGVjdCB0aGUgZ2VuZXMgb2Ygb3VyIGludGVyZXN0LgoKYGBge3IgZXhwcmVzc2lvbl9kYXRhX3NlbGVjdGlvbn0KZXhwcmVzc2lvbl9kYXRhIDwtIGFzc2F5KEFFUk5BU2NvbWJvU0UpCgojIGV4dHJhY3QgZXhwcmVzc2lvbiB2YWx1ZXMgZnJvbSB2c2QsIGluY2x1ZGluZyBlbnNlbWJsIG5hbWVzCmV4cHJlc3Npb25fZGF0YSA8LSBhc190aWJibGUoZGF0YS5mcmFtZShnZW5lX2Vuc2VtYmwgPSByb3dSYW5nZXMoQUVSTkFTY29tYm9TRSkkZmVhdHVyZV9pZCwgYXNzYXkoQUVSTkFTY29tYm9TRSkpKSAlPiUKICAgICBtdXRhdGVfYXQodmFycyhjKCJnZW5lX2Vuc2VtYmwiKSksIGxpc3QoYXMuY2hhcmFjdGVyKSkgIyMgZ2VuZV9lbnNlbWJsIG5lZWRzIHRvIGJlIGNoYXJhY3RlciBmb3IgYW5ub3RhdGlvbiB0byB3b3JrCgojIGFubm90YXRpb25zCiMgZ2VuZSBzeW1ib2wgLSB2aWEgb3JnLkhzLmVnLmRiCiMgY29sdW1ucyhvcmcuSHMuZWcuZGIpCmV4cHJlc3Npb25fZGF0YSRzeW1ib2wgPC0gbWFwSWRzKG9yZy5Icy5lZy5kYiwKICAgICAgICAgICAgICAgICAgICBrZXlzID0gZXhwcmVzc2lvbl9kYXRhJGdlbmVfZW5zZW1ibCwKICAgICAgICAgICAgICAgICAgICBjb2x1bW4gPSAiU1lNQk9MIiwKICAgICAgICAgICAgICAgICAgICBrZXl0eXBlID0gIkVOU0VNQkwiLAogICAgICAgICAgICAgICAgICAgIG11bHRpVmFscyA9ICJmaXJzdCIpCgojIHRpZHkgYW5kIHN1YnNldApleHByZXNzaW9uX2RhdGFfc2VsIDwtIGV4cHJlc3Npb25fZGF0YSAlPiUKICAgICBkcGx5cjo6c2VsZWN0KGdlbmVfZW5zZW1ibCwgc3ltYm9sLCBldmVyeXRoaW5nKCkpICU+JQogICAgICMgZmlsdGVyKHN5bWJvbCA9PSAiQVBPRSIgfCBzeW1ib2wgPT0gIlRSSUIzIikgJT4lICMgZmlsdGVyIEFQT0UgYW5kIFRSSUIzCiAgICAgZHBseXI6OmZpbHRlcihzeW1ib2wgJWluJSBnZW5lX2xpc3QpCgpoZWFkKGV4cHJlc3Npb25fZGF0YV9zZWwpCgojIHRpZHkgYW5kIHN1YnNldCBub24tc2VsZWN0ZWQgZ2VuZXMKc2V0LnNlZWQoMTQxNjE5KQpleHByZXNzaW9uX2RhdGFfc2FtcGxlIDwtIGV4cHJlc3Npb25fZGF0YSAlPiUKICAgICBkcGx5cjo6c2VsZWN0KGdlbmVfZW5zZW1ibCwgc3ltYm9sLCBldmVyeXRoaW5nKCkpICU+JQogICAgIHNhbXBsZV9uKDEwMDApICU+JQogICAgIHVuaXRlKHN5bWJvbF9lbnNlbWJsLCBzeW1ib2wsIGdlbmVfZW5zZW1ibCwgc2VwID0gIl8iLCByZW1vdmUgPSBGQUxTRSkKCmV4cHJlc3Npb25fZGF0YV9zYW1wbGVfbWVhbiA8LSBleHByZXNzaW9uX2RhdGFfc2FtcGxlICU+JQogIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUKICBjb2xNZWFucygpICU+JQogIGFzX3RpYmJsZShyb3duYW1lcyA9ICJzdHVkeV9udW1iZXIiKSAlPiUKICBkcGx5cjo6cmVuYW1lKGV4cHJlc3Npb25fdmFsdWVfc2FtcGxlID0gdmFsdWUpCgpgYGAKCkZ1cnRoZXJtb3JlLCB0aGUgZXhwcmVzc2lvbl9kYXRhX3NlbCBkZiB3YXMgZ2F0aGVyZWQgaW50byBhIGxvbmcgZm9ybSBgZGZgIGZvciBhbm5vdGF0aW9uIHdpdGggc3ltcHRvbXMgdmFyaWFibGVzIGZyb20gdGhlIGB2c2RgIG9iamVjdCwgYW5kIGxhdGVyIHZpc3VhbGl6YXRpb24gYW5kIHN0YXRpc3RpY3MuCgpgYGB7ciBnYXRoZXJ9CiMgZ2F0aGVyIGV4cHJlc3Npb25fZGF0YV9zZWwgZGYgaW50byBsb25nIGRmIGZvcm0gZm9yIGFubm90YXRpb24sIHBsb3R0aW5nIGFuZCBzdGF0aXN0aWNzCmV4cHJlc3Npb25fbG9uZyA8LQogICAgIGdhdGhlcihleHByZXNzaW9uX2RhdGFfc2VsLCBrZXkgPSAic3R1ZHlfbnVtYmVyIiwgdmFsdWUgPSAiZXhwcmVzc2lvbl92YWx1ZSIsIC1jKGdlbmVfZW5zZW1ibCwgc3ltYm9sKSkKCiMgb2xkIHNjaG9vbCB3YXkKIyBBbm5vdGF0ZSB3aXRoIHNtb2tpbmcgdmFyaWFibGVzCiMgc2FtcGxlX2lkcyA8LSBleHByZXNzaW9uX2xvbmckc3R1ZHlfbnVtYmVyCiMgbW0gPC0gbWF0Y2goZXhwcmVzc2lvbl9sb25nJHN0dWR5X251bWJlciwgcm93bmFtZXMoY29sRGF0YSh2c2QpKSkKIwojICMjIEFkZCB0cmFpdHMgdG8gZGYKIyAjIyBCaW5hcnkgdHJhaXRzCiMgZXhwcmVzc2lvbl9sb25nJHNleCA8LSBjb2xEYXRhKHZzZCkkc2V4W21tXQojIGV4cHJlc3Npb25fbG9uZyR0ZXN0b3N0ZXJvbmUgPC0gY29sRGF0YSh2c2QpJHRlc3Rvc3Rlcm9uZVttbV0KIyBleHByZXNzaW9uX2xvbmckdF9lMl9yYXRpbyA8LSBjb2xEYXRhKHZzZCkkdF9lMl9yYXRpb1ttbV0KCiMgbmV3IHNjaG9vbCB3YXkKcGxhcXVlX3BoZW5vdHlwZXNfY2F0IDwtIGMoIk1hY3JvcGhhZ2VzLmJpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTUMuYmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNhbGMuYmluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbGxhZ2VuLmJpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJGYXQuYmluXzEwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICMgIkZhdC5iaW5fNDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiSVBILmJpbiIpCgpwbGFxdWVfcGhlbm90eXBlc19udW0gPC0gYygiTUFDX3JhbmtOb3JtIiwgIyJtYWNtZWFuMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTUNfcmFua05vcm0iLCAjInNtY21lYW4wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAiTWFzdENlbGxzX3JhbmtOb3JtIiwgIyJtYXN0X2NlbGxzX3BsYXF1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICMgIk5ldXRyb3BoaWxzX3JhbmtOb3JtIiwgIyJuZXV0cm9waGlscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJWZXNzZWxEZW5zaXR5X3JhbmtOb3JtIikKCmV4cHJlc3Npb25fbG9uZyA8LSBleHByZXNzaW9uX2xvbmcgJT4lCiAgbGVmdF9qb2luKGJ1bGtSTkFfbWV0YV9jbGluICU+JSBkcGx5cjo6c2VsZWN0KHN0dWR5X251bWJlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxhcXVlX3BoZW5vdHlwZXNfY2F0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFxdWVfcGhlbm90eXBlc19udW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVwbWFqb3IuM3llYXJzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2VwbWFqb3IuMzBkYXlzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBc3ltcHRTeW1wdDJHLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5kZXIsIEhvc3BpdGFsLCBTdHVkeU5hbWUpLAogICAgICAgICAgICBieSA9ICJzdHVkeV9udW1iZXIiKSAlPiUKICBtdXRhdGUoZXBtYWpvcl8zeWVhcnNfeW4gPSBzdHJfcmVwbGFjZV9hbGwoZXBtYWpvci4zeWVhcnMsIGMoIkV4Y2x1ZGVkIiA9ICJ5ZXMiLCAiSW5jbHVkZWQiID0gIm5vIikpKSAjJT4lCiAgIyBtdXRhdGUoZXBtYWpvci4zMGRheXNfeW4gPSBzdHJfcmVwbGFjZV9hbGwoZXBtYWpvci4zMGRheXMsIGMoIkV4Y2x1ZGVkIiA9ICJ5ZXMiLCAiSW5jbHVkZWQiID0gIm5vIikpKQoKaGVhZChleHByZXNzaW9uX2xvbmcpCgojIGV4cHJlc3Npb25fbG9uZyAlPiUKIyAgIHdyaXRlX3RzdigiZ2VuZXNfaW50ZXJlc3RfZXhwcmVzc2lvbi50eHQiKQoKYGBgCgojIyBHZW5lIGV4cHJlc3Npb24gLSBkaXN0cmlidXRpb24KCiMjIyBGaWx0ZXIgZ2VuZXMKCkluIGNhc2Ugc29tZSBnZW5lcyBhcmUgbm90IGF2YWlsYWJsZSBpbiBvdXIgZGF0YSB3ZSBjb3VsZCBmaWx0ZXIgdGhlbSBoZXJlLgoKYGBge3IgbGlzdCB0YXJnZXQgZ2VuZXN9CmdlbmVfbGlzdApgYGAKClRoaXMgY29kZSBpcyBqdXN0IGFuIGV4YW1wbGUgdG8gZmlsdGVyIHRoZSBsaXN0IGZyb20gZ2VuZXMgdGhhdCBhcmUgbm90IGluIHRoZSBkYXRhLgoKLSBfQ09MM0FfID09PiBub3QgZm91bmQKLSBfQ09MMkFfID09PiBub3QgZm91bmQKCmBgYHtyIGZpbHRlciB0YXJnZXQgZ2VuZXN9CmdlbmVfbGlzdF9ybSA8LSBjKCJDT0wzQSIsICJDT0wyQSIpIAoKdGVtcCA9IGdlbmVfbGlzdFshZ2VuZV9saXN0ICVpbiUgZ2VuZV9saXN0X3JtXQoKZ2VuZV9saXN0X3FjIDwtIGModGVtcCkKCiMgZ2VuZV9saXN0X3FjIDwtIGdlbmVfbGlzdAojIAojIGZvciBkZWJ1ZwojIGdlbmVfbGlzdF9xY19yZXBsYWNlIDwtIGMoIk1SVEZBIikKCgpgYGAKCiMjIyBQbG90dGluZyBleHByZXNzaW9uCgoqKkZpZ3VyZSAxOiBFeHByZXNzaW9uIG9mIGdlbmVzIG9mIGludGVyZXN0OiBib3hwbG90cyoqCgpgYGB7ciBib3hwbG90c19leHByZXNzaW9ufQojIE1ha2UgZGlyZWN0b3J5IGZvciBwbG90cwppZmVsc2UoIWRpci5leGlzdHMoZmlsZS5wYXRoKFFDX2xvYywgIi9Cb3hwbG90cyIpKSwgCiAgICAgICBkaXIuY3JlYXRlKGZpbGUucGF0aChRQ19sb2MsICIvQm94cGxvdHMiKSksIAogICAgICAgRkFMU0UpCkJPWF9sb2MgPSBwYXN0ZTAoUUNfbG9jLCIvQm94cGxvdHMiKQoKZm9yKEdFTkUgaW4gZ2VuZV9saXN0X3FjKXsKICBjYXQocGFzdGUwKCJQbG90dGluZyBleHByZXNzaW9uIGZvciAiLCBHRU5FLCIuXG4iKSkKICB0ZW1wIDwtIHN1YnNldChleHByZXNzaW9uX2xvbmcsIHN5bWJvbCA9PSBHRU5FKQogIAogIGNvbXBhcmVfbWVhbnMoZXhwcmVzc2lvbl92YWx1ZSB+IEdlbmRlciwgZGF0YSA9IHRlbXApCiAgcDEgPC0gZ2dwdWJyOjpnZ2JveHBsb3QodGVtcCwKICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gIkdlbmRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICJleHByZXNzaW9uX3ZhbHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJHZW5kZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAibnBnIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBhZGQgPSAiaml0dGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gcGFzdGUwKCJub3JtYWxpemVkIGV4cHJlc3Npb24gIiwgR0VORSwiIiApLAogICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGVsID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKyBzdGF0X2NvbXBhcmVfbWVhbnMoKQogIHByaW50KHAxKQogIGNhdChwYXN0ZTAoIlNhdmluZyBpbWFnZSBmb3IgIiwgR0VORSwiLlxuIikpCiAgCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKEJPWF9sb2MsICIvIiwgVG9kYXksICIuIixHRU5FLCIuZXhwcmVzc2lvbl92c19nZW5kZXIucG5nIiksIHBsb3QgPSBsYXN0X3Bsb3QoKSkKICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoQk9YX2xvYywgIi8iLCBUb2RheSwgIi4iLEdFTkUsIi5leHByZXNzaW9uX3ZzX2dlbmRlci5wZGYiKSwgcGxvdCA9IGxhc3RfcGxvdCgpKQogIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChCT1hfbG9jLCAiLyIsIFRvZGF5LCAiLiIsR0VORSwiLmV4cHJlc3Npb25fdnNfZ2VuZGVyLnBzIiksIHBsb3QgPSBsYXN0X3Bsb3QoKSkKCiAgCiAgcm0odGVtcCwgcDEpCn0KCmBgYAoKKipGaWd1cmUgMkE6IEV4cHJlc3Npb24gb2YgZ2VuZXMgb2YgaW50ZXJlc3Q6IGhpc3RvZ3JhbXMqKgoKYGBge3IgaGlzdF9leHByZXNzaW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIE1ha2UgZGlyZWN0b3J5IGZvciBwbG90cwppZmVsc2UoIWRpci5leGlzdHMoZmlsZS5wYXRoKFFDX2xvYywgIi9IaXN0b2dyYW1zIikpLCAKICAgICAgIGRpci5jcmVhdGUoZmlsZS5wYXRoKFFDX2xvYywgIi9IaXN0b2dyYW1zIikpLCAKICAgICAgIEZBTFNFKQpISVNUT0dSQU1fbG9jID0gcGFzdGUwKFFDX2xvYywiL0hpc3RvZ3JhbXMiKQoKZm9yKEdFTkUgaW4gZ2VuZV9saXN0X3FjKXsKICAjIGNhdChwYXN0ZTAoIlBsb3R0aW5nIGV4cHJlc3Npb24gZm9yICIsIEdFTkUsIi5cbiIpKQogIHRlbXAgPC0gc3Vic2V0KGV4cHJlc3Npb25fbG9uZywgc3ltYm9sID09IEdFTkUpCiAgcDEgPC0gZ2dwdWJyOjpnZ2hpc3RvZ3JhbSh0ZW1wLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAiZXhwcmVzc2lvbl92YWx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICIuLmNvdW50Li4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIkdlbmRlciIsIGZpbGwgPSAiR2VuZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIm5wZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkID0gIm1lZGlhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYiA9IHBhc3RlMCgibm9ybWFsaXplZCBleHByZXNzaW9uICIsIEdFTkUsIiIgKSAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgKQogIHByaW50KHAxKQogIGNhdChwYXN0ZTAoIlNhdmluZyBpbWFnZSBmb3IgIiwgR0VORSwiLlxuIikpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKEhJU1RPR1JBTV9sb2MsICIvIiwgVG9kYXksICIuIixHRU5FLCIuZGlzdHJpYnV0aW9uLnBuZyIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKEhJU1RPR1JBTV9sb2MsICIvIiwgVG9kYXksICIuIixHRU5FLCIuZGlzdHJpYnV0aW9uLnBkZiIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKEhJU1RPR1JBTV9sb2MsICIvIiwgVG9kYXksICIuIixHRU5FLCIuZGlzdHJpYnV0aW9uLnBzIiksIHBsb3QgPSBsYXN0X3Bsb3QoKSkKCiAgcm0odGVtcCwgcDEgKQp9CgpgYGAKCioqRmlndXJlIDJCOiBFeHByZXNzaW9uIG9mIGdlbmVzIG9mIGludGVyZXN0OiBkZW5zaXR5IHBsb3RzKioKCmBgYHtyIGRlbnNfZXhwcmVzc2lvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBNYWtlIGRpcmVjdG9yeSBmb3IgcGxvdHMKaWZlbHNlKCFkaXIuZXhpc3RzKGZpbGUucGF0aChRQ19sb2MsICIvRGVuc2l0eSIpKSwgCiAgICAgICBkaXIuY3JlYXRlKGZpbGUucGF0aChRQ19sb2MsICIvRGVuc2l0eSIpKSwgCiAgICAgICBGQUxTRSkKREVOU0lUWV9sb2MgPSBwYXN0ZTAoUUNfbG9jLCIvRGVuc2l0eSIpCgpmb3IoR0VORSBpbiBnZW5lX2xpc3RfcWMpewogICMgY2F0KHBhc3RlMCgiUGxvdHRpbmcgZXhwcmVzc2lvbiBmb3IgIiwgR0VORSwiLlxuIikpCiAgdGVtcCA8LSBzdWJzZXQoZXhwcmVzc2lvbl9sb25nLCBzeW1ib2wgPT0gR0VORSkKICBwMSA8LSBnZ3B1YnI6OmdnaGlzdG9ncmFtKHRlbXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJleHByZXNzaW9uX3ZhbHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gIi4uZGVuc2l0eS4uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJHZW5kZXIiLCBmaWxsID0gIkdlbmRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJucGciLAogICAgICAgICAgICAgICAgICAgICAgICAgIGFkZCA9ICJtZWRpYW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSBwYXN0ZTAoIm5vcm1hbGl6ZWQgZXhwcmVzc2lvbiAiLCBHRU5FLCIiICkgIAogICAgICAgICAgICAgICAgICAgICAgICAgICkKICBwcmludChwMSkKICBjYXQocGFzdGUwKCJTYXZpbmcgaW1hZ2UgZm9yICIsIEdFTkUsIi5cbiIpKQogIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChERU5TSVRZX2xvYywgIi8iLCBUb2RheSwgIi4iLEdFTkUsIi5kZW5zaXR5LnBuZyIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKERFTlNJVFlfbG9jLCAiLyIsIFRvZGF5LCAiLiIsR0VORSwiLmRlbnNpdHkucGRmIiksIHBsb3QgPSBsYXN0X3Bsb3QoKSkKICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoREVOU0lUWV9sb2MsICIvIiwgVG9kYXksICIuIixHRU5FLCIuZGVuc2l0eS5wcyIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgCiAgcm0odGVtcCwgcDEgKQp9CgpgYGAKCiMjIENvbXBhcmUgZXhwcmVzc2lvbiB0byB0aGUgZXhwcmVzc2lvbiBvZiBhIHNhbXBsZSBvZiAxLDAwMCBnZW5lcwoKKipGaWd1cmUgMzogY29tcGFyaW5nIGV4cHJlc3Npb24gb2YgZ2VuZXMgb2YgaW50ZXJlc3QgdG8gbWVhbiBleHByZXNzaW9uIG9mIGEgc2FtcGxlIG9mIDEsMDAwIHJhbmRvbSBnZW5lcyoqCgpgYGB7ciBib3hwbG90c19leHByZXNzaW9uX2NvbXBhcmlzb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpleHByZXNzaW9uX3dpZGUgPC0gZXhwcmVzc2lvbl9sb25nICU+JQogIHRpZHlyOjp1bml0ZSgic3ltYm9sX2Vuc2VtYmwiLCBzeW1ib2w6Z2VuZV9lbnNlbWJsLCByZW1vdmUgPSBUUlVFLCBzZXAgPSAiXyIpICU+JQogICMgZHBseXI6OnNlbGVjdCgtZ2VuZV9lbnNlbWJsLCAtc3ltYm9sKSAlPiUKICB0aWR5cjo6c3ByZWFkKGtleSA9IHN5bWJvbF9lbnNlbWJsLCB2YWx1ZSA9IGV4cHJlc3Npb25fdmFsdWUpIAoKYGBgCgpgYGB7ciB9CiMgdGhlIG5leHQgMyBsaW5lcyBvZiBjb2RlIGdhdmUgYW4gZXJyb3Igd2hlbiBzZWxlY3RpbmcgZm9yIGdlbmVzX2ludGVyZXN0LCBzaW5jZSBvbmUgb2YgdGhlIGdlbmVzIG9mIGludGVyZXN0IGlzIG1pc3Npbmc6IEZHRjMgaXMgbm90IGluIHRoZSBkYXRhIHNldC4gU28sIHdlIG5lZWQgdG8gc2VsZWN0IGZvciB0aGUgb3RoZXIgMTUgZ2VuZXMuCgp0ZW1wIDwtIGV4cHJlc3Npb25fbG9uZyAlPiUKICB0aWR5cjo6dW5pdGUoInN5bWJvbF9lbnNlbWJsIiwgc3ltYm9sOmdlbmVfZW5zZW1ibCwgcmVtb3ZlID0gVFJVRSwgc2VwID0gIl8iKSAlPiUKICBkcGx5cjo6c2VsZWN0KHN5bWJvbF9lbnNlbWJsKQp0ZW1wIDwtIHRlbXAgJT4lIAogIHRpZHlyOjpzZXBhcmF0ZShzeW1ib2xfZW5zZW1ibCwgYygic3ltYm9sIiwgImdlbmVfZW5zZW1ibCIpLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgZHBseXI6OmRpc3RpbmN0KC4sIHN5bWJvbF9lbnNlbWJsLCAua2VlcF9hbGwgPSBUUlVFKQoKc3ltYm9sX2Vuc2VtYmxfZ2VuZV9saXN0X3FjIDwtIHRlbXBbdGVtcCRzeW1ib2wgJWluJSBnZW5lX2xpc3RfcWMsXSRzeW1ib2xfZW5zZW1ibApgYGAKCmBgYHtyfQpleHByZXNzaW9uX3dpZGUyIDwtIGV4cHJlc3Npb25fd2lkZSAlPiUKICBsZWZ0X2pvaW4oZXhwcmVzc2lvbl9kYXRhX3NhbXBsZV9tZWFuLCBieSA9ICJzdHVkeV9udW1iZXIiKSAlPiUKICBkcGx5cjo6c2VsZWN0KHN0dWR5X251bWJlciwgU3R1ZHlOYW1lLCBzeW1ib2xfZW5zZW1ibF9nZW5lX2xpc3RfcWMsIGV4cHJlc3Npb25fdmFsdWVfc2FtcGxlKQoKZXhwcmVzc2lvbl9sb25nMiA8LSBleHByZXNzaW9uX3dpZGUyICU+JQogIGdhdGhlcihnZW5lLCBleHByZXNzaW9uX3ZhbHVlLCAtc3R1ZHlfbnVtYmVyLCAtU3R1ZHlOYW1lKSAlPiUKICBtdXRhdGUoZ2VuZSA9IHN0cl9yZXBsYWNlX2FsbChnZW5lLCBjKCJleHByZXNzaW9uX3ZhbHVlX3NhbXBsZSIgPSAiUmFuZG9tIGdlbmVzIikpKSAjJT4lCiAgIyBtdXRhdGUoZ2VuZSA9IGZhY3RvcihnZW5lLCBsZXZlbHMgPSBjKCJSYW5kb20gZ2VuZXMiLCBnZW5lX2xpc3RfcWMpKSkKZXhwcmVzc2lvbl9sb25nMgptZWFuXzEwMDBfZ2VuZXMgPC0gbWVhbihleHByZXNzaW9uX2RhdGFfc2FtcGxlX21lYW4kZXhwcmVzc2lvbl92YWx1ZV9zYW1wbGUpCiMgaGVhZChleHByZXNzaW9uX2xvbmcyKQojIAoKICBwMSA8LSBnZ3B1YnI6OmdnYm94cGxvdChleHByZXNzaW9uX2xvbmcyLAogICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAiZ2VuZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9ICJleHByZXNzaW9uX3ZhbHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHVpdGhvZl9jb2xvclsxNl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkID0gImppdHRlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkLnBhcmFtcyA9IGxpc3Qoc2l6ZSA9IDMsIGppdHRlciA9IDAuMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSBwYXN0ZTAoIm5vcm1hbGl6ZWQgZXhwcmVzc2lvbiAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbl8xMDAwX2dlbmVzLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9IHVpdGhvZl9jb2xvclsyNl0sIHNpemUgPSAwLjQpICsgCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxKSwgIyBjaGFuZ2Ugb3JpZW50YXRpb24gb2YgeC1heGlzIGxhYmVscwogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpIAogIHAxCiAgCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKFBMT1RfbG9jLCAiLyIsIFRvZGF5LCAiLlRhcmdldEV4cHJlc3Npb25fdnNfMTAwMGdlbmVzLnBuZyIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKFBMT1RfbG9jLCAiLyIsIFRvZGF5LCAiLlRhcmdldEV4cHJlc3Npb25fdnNfMTAwMGdlbmVzLnBkZiIpLCBwbG90ID0gbGFzdF9wbG90KCkpCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKFBMT1RfbG9jLCAiLyIsIFRvZGF5LCAiLlRhcmdldEV4cHJlc3Npb25fdnNfMTAwMGdlbmVzLnBzIiksIHBsb3QgPSBsYXN0X3Bsb3QoKSkKCiAgcm0ocDEsIHRlbXAgKQoKCmBgYAoKIyMgSGVhdG1hcHMgZm9yIGdlbmVzIG9mIGludGVyZXN0CgpJZiB3ZSB3b3VsZCBwdXQgdGhlc2UgY29ycmVsYXRpb25zIGluIG9uZSBzaW1wbGUgYW5kIGNvbXByZWhlbnNpYmxlIGZpZ3VyZSwgd2UgY291bGQgdXNlIGEgY29ycmVsYXRpb24gaGVhdG1hcC4gQWdhaW4sIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyB1c2VkIGhlcmUgYXJlIFNwZWFybWFuJ3MuCgoqKkZpZ3VyZSA0OiBjb3JyZWxhdGlvbiBoZWF0bWFwIGJldHdlZW4gZXhwcmVzc2lvbiBvZiBnZW5lcyBvZiBpbnRlcmVzdCoqCgpgYGB7ciBoZWF0bWFwX2NvcnJfZ2VuZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1hZ3JpdHRyKQoKdGVtcCA8LSBleHByZXNzaW9uX3dpZGUgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJzdHVkeV9udW1iZXIiKSAlPiUKICBkcGx5cjo6c2VsZWN0KHN5bWJvbF9lbnNlbWJsX2dlbmVfbGlzdF9xYykgJT4lIAogIGRyb3BfbmEoKSAlPiUgIyBkcm9wIE5BIAogIEZpbHRlcihmdW5jdGlvbih4KSBzZCh4KSAhPSAwLCAuKSAjIGZpbHRlciB2YXJpYWJsZXMgd2l0aCBzZCA9IDAKCnRlbXAuY29yIDwtIGNvcih0ZW1wLCBtZXRob2QgPSAic3BlYXJtYW4iKSAKCnAxIDwtIHBoZWF0bWFwKGRhdGEubWF0cml4KHRlbXAuY29yKSwgCiAgICAgICAgICAgICAgIHNjYWxlID0gIm5vbmUiLAogICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSwKICAgICAgICAgICAgICAgbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgZm9udHNpemUgPSAxMCkKcDEKCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChQTE9UX2xvYywgIi8iLCBUb2RheSwgIi5jb3JyZWxhdGlvbnMuZ2VuZV9saXN0LnBkZiIpLCBwbG90ID0gcDEsIGhlaWdodCA9IDE1LCB3aWR0aCA9IDE1KQoKZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKFBMT1RfbG9jLCAiLyIsIFRvZGF5LCAiLmNvcnJlbGF0aW9ucy5nZW5lX2xpc3QucG5nIiksIHBsb3QgPSBwMSwgaGVpZ2h0ID0gMTUsIHdpZHRoID0gMTUpCgoKcm0odGVtcCwgdGVtcC5jb3IsIHAxKQoKYGBgCgojIEdlbmUgdGFyZ2V0IGxpc3QKCldlIGFyZSBzYXZpbmcgdGhlIGZpbmFsIGxpc3Qgb2YgZ2VuZXMgb2YgaW50ZXJlc3QKCmBgYHtyIFNhdmUgdGFyZ2V0IGdlbmVzfQoKdGVtcCA8LSBzdWJzZXQoZXhwcmVzc2lvbl9kYXRhX3NlbCwgc2VsZWN0ID0gYygiZ2VuZV9lbnNlbWJsIiwgInN5bWJvbCIpKQoKZndyaXRlKHRlbXAsCiAgICAgICBmaWxlID0gcGFzdGUwKE9VVF9sb2MsICIvIiwgVG9kYXksICIudGFyZ2V0X2xpc3QucWMudHh0IiksCiAgICAgICBzZXAgPSAiICIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBUUlVFLAogICAgICAgc2hvd1Byb2dyZXNzID0gVFJVRSkKCmBgYAoKIyBTYXZpbmcgQUVSTkEgZGF0YSBzdWJzZXQKCldlIHdpbGwgY3JlYXRlIGEgbGlzdCBvZiBzYW1wbGVzIHRoYXQgc2hvdWxkIGJlIGluY2x1ZGVkIGJhc2VkIG9uIENFQSwgYW5kIGhhdmluZyB0aGUgcHJvcGVyIGluZm9ybWVkIGNvbnNlbnQgKCdhY2FkZW1pYycpLiBXZSB3aWxsIHNhdmUgdGhlIGBTdW1tYXJpemVkRXhwZXJpbWVudGAgYXMgYSBSRFMgZmlsZSBmb3IgZWFzeSBsb2FkaW5nLiBUaGUgY2xpbmljYWwgZGF0YSB3aWxsIGFsc28gYmUgc2F2ZWQgYXMgYSBzZXBhcmF0ZSBgdHh0YC1maWxlLgoKVG8gdGhpcyBlbmQgeW91IG5lZWQgdG8gbG9va3VwIHRoZSBFbnNlbWJsSUQgKHNlZSBhYm92ZSkgZm9yIHlvdXIgdGFyZ2V0KHMpLgoKYGBge3J9CiMgdGFyZ2V0cyA9IGMoIkVOU0cwMDAwMDE2NjAzMyIsICMgdGFyZ2V0CiMgICAgICAgICAgICAgIkVOU0cwMDAwMDE2OTE3NCIpICMgcG9zaXRpdmUgY29udHJvbCBQQ1NLOQojIHRhcmdldHMgPSBjKCJFTlNHMDAwMDAxNjkxNzQiKSAjIHRhcmdldC9wb3NpdGl2ZSBjb250cm9sIFBDU0s5Cgp0YXJnZXRzID0gdW5saXN0KHRlbXAkZ2VuZV9lbnNlbWJsKQoKcm0odGVtcCkKYGBgCgoKIyMgQ3JlYXRlIGEgU3VtbWFyaXplZEV4cGVyaW1lbnQKCldlIG1ha2UgYSBgU3VtbWFyaXplZEV4cGVyaW1lbnRgIGZvciB0aGUgc3Vic2V0IG9mIFJOQXNlcSBkYXRhLiBXZSBtYWtlIHN1cmUgdG8gb25seSBpbmNsdWRlIHRoZSBzYW1wbGVzIHdlIG5lZWQgYmFzZWQgb24gaW5mb3JtZWQgY29uc2VudCBhbmQgd2UgaW5jbHVkZSBvbmx5IHRoZSByZXF1ZXN0ZWQgdmFyaWFibGVzLgoKTmV4dCwgd2UgYXJlIGNvbnN0cnVjdGluZyB0aGUgYFN1bW1hcml6ZWRFeHBlcmltZW50YC4KYGBge3IgUk5Bc2VxIHRvIFNFfQoKQUVSTkFTX21ldGFfZGF0YSA9IGMoIlNhbXBsZVR5cGUiLCAiUk5Bc2VxVGVjaCIsICJSTkFzZXFUeXBlIiwgIlJOQXNlcVFDIiwKICAgICAgICAgICAgICAgICAgICAgIlN0dWR5VHlwZSIsICJTdHVkeU5hbWUiLCAiU3R1ZHlCaW9iYW5rIiwgIlNhbXBsZVNpemUiKQoKY2F0KCJcbiogbWFraW5nIGEgU3VtbWFyaXplZEV4cGVyaW1lbnQgLi4uXG4iKQojIHRoaXMgaXMgYWxsIHRoZSBkYXRhIHBhc3NpbmcgUk5Bc2VxIHF1YWxpdHkgY29udHJvbCBhbmQgVU1JLWNvcnJlY3RlZAojIC0gYWZ0ZXIgZmlsdGVyaW5nIG9uIGluZm9ybWVkIGNvbnNlbnQgYW5kIGFydGVyeSB0eXBlLCB0aGUgZW5kIHNhbXBsZSBzaXplIHNob3VsZCBiZSAxMDkzCiMgLSBhZnRlciBmaWx0ZXJpbmcgb24gJ25vIGNvbW1lcmNpYWwgYnVzaW5lc3MnIGJhc2VkIG9uIGluZm9ybWVkIGNvbnNlbnQsIHRoZXJlIGFyZSBmZXdlciBzYW1wbGVzOiB5eXl5CmNhdCgiICA+IGdldHRpbmcgY291bnRzXG4iKQpidWxrUk5BX2NvdW50c0ZpbHQgPC0gYXMuZGF0YS5mcmFtZShhc3NheShBRVJOQVNjb21ib1NFW3RhcmdldHMsXSkpCmRpbShidWxrUk5BX2NvdW50c0ZpbHQpCmhlYWQoYnVsa1JOQV9jb3VudHNGaWx0KQoKY2F0KCIgID4gbWV0YSBkYXRhIGFuZCBjbGluaWNhbCBkYXRhXG4iKQojIGJ1bGtSTkFfbWV0YV9jbGluX0NPTU1FUkNJQUwgPC0gc3Vic2V0KGJ1bGtSTkFfbWV0YV9jbGluLCBzZWxlY3QgPSBjKCJzdHVkeV9udW1iZXIiLCBiYXNldGFibGVfdmFycykpCmJ1bGtSTkFfbWV0YV9jbGluX0FDQURFTUlDIDwtIHN1YnNldChidWxrUk5BX21ldGFfY2xpbiwgc2VsZWN0ID0gYygic3R1ZHlfbnVtYmVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBRVJOQVNfbWV0YV9kYXRhLCAjIG1ldGEgZGF0YSBvZiBSTkFzZXEgZXhwZXJpbWVudAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZXRhYmxlX3ZhcnMpKSAjIHNlbGVjdGlvbiBvZiB2YXJpYWJsZXMKZGltKGJ1bGtSTkFfbWV0YV9jbGluX0FDQURFTUlDKQpoZWFkKGJ1bGtSTkFfbWV0YV9jbGluX0FDQURFTUlDKQoKY2F0KCIgID4gcm93UmFuZ2VzXG4iKQojIGJ1bGtSTkFfbWV0YV9jbGluX0NPTU1FUkNJQUwgPC0gc3Vic2V0KGJ1bGtSTkFfbWV0YV9jbGluLCBzZWxlY3QgPSBjKCJzdHVkeV9udW1iZXIiLCBiYXNldGFibGVfdmFycykpCmJ1bGtSTkFfcm93UmFuZ2VzIDwtIHJvd1JhbmdlcyhBRVJOQVNjb21ib1NFW3RhcmdldHNdKQpidWxrUk5BX3Jvd1JhbmdlcwoKY2F0KCIgID4gY29uc3RydWN0aW9uIG9mIHRoZSBTRVxuIikKKEFFUk5BU2NvbWJvU0VfdGFyZ2V0IDwtIFN1bW1hcml6ZWRFeHBlcmltZW50KGFzc2F5cyA9IGxpc3QoY291bnRzID0gYXMubWF0cml4KGJ1bGtSTkFfY291bnRzRmlsdCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGJ1bGtSTkFfbWV0YV9jbGluX0FDQURFTUlDLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93UmFuZ2VzID0gYnVsa1JOQV9yb3dSYW5nZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YSA9ICJBdGhlcm8tRXhwcmVzcyBCaW9iYW5rIFN0dWR5IGJ1bGsgUk5BIHNlcXVlbmNpbmcuIFNhbXBsZSB0eXBlOiBjYXJvdGlkIHBsYXF1ZXMuIFRlY2hub2xvZ3k6IENFTDItc2VxIGFkYXB0ZWQgZm9yIGJ1bGsgUk5BIHNlcXVlbmNpbmcsIHRodXMgMyctZm9jdXNlZC4gVU1JLWNvcnJlY3RlZC4gVlNUIGFuZCBzaXplIGZhY3RvciBub3JtYWxpemVkLiBUYXJnZXQgc3Vic2V0LiIpKQoKY2F0KCJcbiogcmVtb3ZpbmcgaW50ZXJtZWRpYXRlIGZpbGVzIC4uLlxuIikKcm0oYnVsa1JOQV9tZXRhX2NsaW5fQUNBREVNSUMsIGJ1bGtSTkFfY291bnRzRmlsdCwgYnVsa1JOQV9yb3dSYW5nZXMpCgpgYGAKCgojIyBTYXZpbmcgZGF0YSBzdWJzZXQKClNhbXBsZSBsaXN0IGFuZCBjbGluaWNhbCBkYXRhLgpgYGB7cn0KdGVtcCA8LSBhcy50aWJibGUoc3Vic2V0KGNvbERhdGEoQUVSTkFTY29tYm9TRV90YXJnZXQpLCBzZWxlY3QgPSBjKCJzdHVkeV9udW1iZXIiLCBBRVJOQVNfbWV0YV9kYXRhKSkpCgpmd3JpdGUodGVtcCwKICAgICAgIGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8iLCBUb2RheSwgIi5BRVJOQVMxU0VfdGFyZ2V0LkNFQS42MjRwdHMuc2FtcGxlbGlzdC5hZnRlcl9xYy5JQ19hY2FkZW1pYy5jc3YiKSwKICAgICAgIHNlcCA9ICIsIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUsCiAgICAgICBzaG93UHJvZ3Jlc3MgPSBUUlVFKQpybSh0ZW1wKQoKdGVtcCA8LSBhcy50aWJibGUoc3Vic2V0KGNvbERhdGEoQUVSTkFTY29tYm9TRV90YXJnZXQpLCBzZWxlY3QgPSBjKCJzdHVkeV9udW1iZXIiLCBiYXNldGFibGVfdmFycykpKQoKZndyaXRlKHRlbXAsCiAgICAgICBmaWxlID0gcGFzdGUwKE9VVF9sb2MsICIvIiwgVG9kYXksICIuQUVSTkFTMVNFX3RhcmdldC5DRUEuNjI0cHRzLmNsaW5pY2FsZGF0YS5hZnRlcl9xYy5JQ19hY2FkZW1pYy5jc3YiKSwKICAgICAgIHNlcCA9ICIsIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUsCiAgICAgICBzaG93UHJvZ3Jlc3MgPSBUUlVFKQpybSh0ZW1wKQpgYGAKCkFzc2F5IGRhdGEgYW5kIGdlbmUgaW5mb3JtYXRpb24uCmBgYHtyfQp0ZW1wIDwtIGFzX3RpYmJsZShhc3NheShBRVJOQVNjb21ib1NFX3RhcmdldCkpCgpmd3JpdGUodGVtcCwKICAgICAgIGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8iLCBUb2RheSwgIi5BRVJOQVMxU0VfdGFyZ2V0LkNFQS42MjRwdHMuYXNzYXkuYWZ0ZXJfcWMuSUNfYWNhZGVtaWMuY3N2IiksCiAgICAgICBzZXAgPSAiLCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBUUlVFLAogICAgICAgc2hvd1Byb2dyZXNzID0gVFJVRSkKcm0odGVtcCkKCnRlbXAgPC0gYXNfdGliYmxlKHJvd1JhbmdlcyhBRVJOQVNjb21ib1NFX3RhcmdldCkpCgpmd3JpdGUodGVtcCwKICAgICAgIGZpbGUgPSBwYXN0ZTAoT1VUX2xvYywgIi8iLCBUb2RheSwgIi5BRVJOQVMxU0VfdGFyZ2V0LkNFQS42MjRwdHMuZ2VuZWRhdGEuYWZ0ZXJfcWMuSUNfYWNhZGVtaWMuY3N2IiksCiAgICAgICBzZXAgPSAiLCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBUUlVFLAogICAgICAgc2hvd1Byb2dyZXNzID0gVFJVRSkKcm0odGVtcCkKYGBgCgpUaGUgc3Vic2V0IGFzIGBTdW1tYXJpemVkRXhwZXJpbWVudCgpYCBkYXRhc2V0IGluIGBSRFNgLWZvcm1hdC4KYGBge3J9CgojIHNhdmVSRFMoQUVSTkFTRSwgZmlsZSA9IHBhc3RlMChPVVRfbG9jLCAiLyIsIFRvZGF5LCAiLkFFUk5BU2NvbWJvU0VfdGFyZ2V0LkNFQS42MDhwdHMuU0UuYWZ0ZXJfcWMuSUNfY29tbWVyY2lhbC5SRFMiKSkKc2F2ZVJEUyhBRVJOQVNjb21ib1NFX3RhcmdldCwgZmlsZSA9IHBhc3RlMChPVVRfbG9jLCAiLyIsIFRvZGF5LCAiLkFFUk5BUzFTRV90YXJnZXQuQ0VBLjYyNHB0cy5TRS5hZnRlcl9xYy5JQ19hY2FkZW1pYy5SRFMiKSkKCmBgYAoKCgojIFNlc3Npb24gaW5mb3JtYXRpb24KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogICAgVmVyc2lvbjogICAgICB2MS4wLjEKICAgIExhc3QgdXBkYXRlOiAgMjAyNS0wMy0yOAogICAgV3JpdHRlbiBieTogICBTYW5kZXIgVy4gdmFuIGRlciBMYWFuIChzLncudmFuZGVybGFhbi0yW2F0XXVtY3V0cmVjaHQubmwpLgogICAgRGVzY3JpcHRpb246ICBTY3JpcHQgdG8gbG9hZCBidWxrIFJOQSBzZXF1ZW5jaW5nIGRhdGEsIGFuZCBwZXJmb3JtIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNlcywgYW5kIHZpc3VhbGlzYXRpb25zLgogICAgTWluaW11bSByZXF1aXJlbWVudHM6IFIgdmVyc2lvbiAzLjUuMiAoMjAxOC0xMi0yMCkgLS0gJ0VnZ3NoZWxsIElnbG9vJywgbWFjT1MgTW9qYXZlICgxMC4xNC4yKS4KCiAgICAqKk1vU0NvVyBUby1EbyBMaXN0KioKICAgIFRoZSB0aGluZ3Mgd2UgTXVzdCwgU2hvdWxkLCBDb3VsZCwgYW5kIFdvdWxkIGhhdmUgZ2l2ZW4gdGhlIHRpbWUgd2UgaGF2ZS4KICAgIF9NXwoKICAgIF9TXwoKICAgIF9DXwoKICAgIF9XXwoKICAgICoqQ2hhbmdlcyBsb2cqKgogICAgKiB2MS4wLjEgVXBkYXRlZCB0aGUgc2NyaXB0IHRvIGluY2x1ZGUgdGhlIGxhdGVzdCBkYXRhIGFuZCB0byBleHBsb3JlIHRoZSBzdWJzZXQgb2YgZGF0YS4KICAgICogdjEuMC4wIEluaXRhbCB2ZXJzaW9uLiBSZS1hcnJhbmdlZCB0byBleHBsb3JlIHRoZSBzdWJzZXQgb2YgZGF0YS4gCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYGBge3IgZXZhbCA9IFRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgojIFNhdmluZyBlbnZpcm9ubWVudAoKYGBge3IgU2F2aW5nfQpzYXZlLmltYWdlKHBhc3RlMChQUk9KRUNUX2xvYywgIi8iLFRvZGF5LCIuIixQUk9KRUNUTkFNRSwiLmJ1bGtSTkFzZXEuZXhwbG9yYXRpb24uUkRhdGEiKSkKYGBgCgorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCnwgPHN1cD7CqSAxOTc5LTIwMjUgU2FuZGVyIFcuIHZhbiBkZXIgTGFhbiB8IHMudy52YW5kZXJsYWFuW2F0XWdtYWlsW2RvdF1jb20gfCBbdmFuZGVybGFhbmFuZC5zY2llbmNlXShodHRwczovL3ZhbmRlcmxhYW5hbmQuc2NpZW5jZSkuPC9zdXA+IHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwo=